PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.1-beta.2
Jetpack – WP Security, Backup, Speed, & Growth v16.1-beta.2
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 / jetpack_vendor / automattic / jetpack-publicize / src / class-publicize.php
jetpack / jetpack_vendor / automattic / jetpack-publicize / src Last commit date
jetpack-social-settings 3 months ago rest-api 3 weeks ago social-image-generator 3 weeks ago class-connections.php 3 weeks ago class-focal-point.php 2 months ago class-keyring-helper.php 2 months ago class-keyring-result-handler.php 2 months ago class-message-templates-placeholders.php 3 months ago class-publicize-assets.php 2 months ago class-publicize-base.php 4 weeks ago class-publicize-script-data.php 1 month ago class-publicize-setup.php 4 weeks ago class-publicize-ui.php 4 weeks ago class-publicize-utils.php 4 weeks ago class-publicize.php 2 months ago class-services.php 3 weeks ago class-share-status.php 9 months ago class-social-admin-page.php 3 weeks ago
class-publicize.php
739 lines
1 <?php
2 /**
3 * Publicize class.
4 *
5 * @package automattic/jetpack-publicize
6 */
7
8 namespace Automattic\Jetpack\Publicize;
9
10 use Automattic\Jetpack\Connection\Client;
11 use Automattic\Jetpack\Connection\Tokens;
12 use Jetpack_IXR_Client;
13 use Jetpack_Options;
14 use WP_Error;
15 use WP_Post;
16
17 /**
18 * Extend the base class with Jetpack-specific functionality.
19 */
20 class Publicize extends Publicize_Base {
21
22 const JETPACK_SOCIAL_CONNECTIONS_TRANSIENT = 'jetpack_social_connections';
23
24 /**
25 * Transitory storage of connection testing results.
26 *
27 * @var array
28 */
29 private $test_connection_results = array();
30
31 /**
32 * Property to store the results of fetching the connections.
33 *
34 * @var null|array
35 */
36 private $current_connections = null;
37
38 /**
39 * Add hooks.
40 */
41 public function __construct() {
42 parent::__construct();
43
44 add_filter( 'jetpack_xmlrpc_unauthenticated_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
45
46 add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
47
48 add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
49
50 add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
51
52 add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 2 );
53
54 add_action( 'connection_disconnected', array( $this, 'add_disconnect_notice' ) );
55 }
56
57 /**
58 * Add a notice when a connection has been disconnected.
59 */
60 public function add_disconnect_notice() {
61 add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
62 }
63
64 /**
65 * Force user connection before showing the Publicize UI.
66 */
67 public function force_user_connection() {
68 global $current_user;
69
70 $user_token = ( new Tokens() )->get_access_token( $current_user->ID );
71 $is_user_connected = $user_token && ! is_wp_error( $user_token );
72
73 // If the user is already connected via Jetpack, then we're good.
74 if ( $is_user_connected ) {
75 return;
76 }
77
78 // If they're not connected, then remove the Publicize UI and tell them they need to connect first.
79 global $publicize_ui;
80 remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
81
82 // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
83 // Jetpack::init()->admin_styles();.
84 add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
85 }
86
87 /**
88 * Show a warning when Publicize does not have a connection.
89 */
90 public function admin_page_warning() {
91 $jetpack = \Jetpack::init();
92 $blog_name = get_bloginfo( 'blogname' );
93 if ( empty( $blog_name ) ) {
94 $blog_name = home_url( '/' );
95 }
96
97 ?>
98 <div id="message" class="updated jetpack-message jp-connect">
99 <div class="jetpack-wrap-container">
100 <div class="jetpack-text-container">
101 <p>
102 <?php
103 printf(
104 /* translators: %s is the name of the blog */
105 esc_html( wptexturize( __( "To use Jetpack Social, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack-publicize-pkg' ) ) ),
106 '<strong>' . esc_html( $blog_name ) . '</strong>'
107 );
108 ?>
109 </p>
110 <p><?php echo esc_html( wptexturize( __( "If you don't have a WordPress.com account yet, you can sign up for free in just a few seconds.", 'jetpack-publicize-pkg' ) ) ); ?></p>
111 </div>
112 <div class="jetpack-install-container">
113 <p class="submit"><a
114 href="<?php echo esc_url( $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ) ); ?>"
115 class="button-connector"
116 id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack-publicize-pkg' ); ?></a>
117 </p>
118 <p class="jetpack-install-blurb">
119 <?php jetpack_render_tos_blurb(); ?>
120 </p>
121 </div>
122 </div>
123 </div>
124 <?php
125 }
126
127 /**
128 * Remove a Publicize Connection.
129 *
130 * @param string $service_name 'facebook', 'twitter', etc.
131 * @param string $connection_id Connection ID.
132 * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
133 * @param false|int $_user_id The user ID. Use false (default) for the current user.
134 * @param bool $force_delete Whether to skip permissions checks.
135 * @return false|void False on failure. Void on success.
136 */
137 public function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
138 return Keyring_Helper::disconnect( $service_name, $connection_id, $_blog_id, $_user_id, $force_delete );
139 }
140
141 /**
142 * Set updated Publicize connections in a transient.
143 *
144 * @param mixed $publicize_connections Updated connections.
145 * @return true
146 */
147 public function receive_updated_publicize_connections( $publicize_connections ) {
148
149 // Populate the cache with the new data.
150 Connections::get_all( array( 'ignore_cache' => true ) );
151
152 $expiry = 3600 * 4;
153 if ( ! set_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT, $publicize_connections, $expiry ) ) {
154 // If the transient has beeen set in another request, the call to set_transient can fail. If so,
155 // we can delete the transient and try again.
156 $this->clear_connections_transient();
157 set_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT, $publicize_connections, $expiry );
158 }
159 // Regardless of whether the transient is set ok, let's set and use the local property for this request.
160 $this->current_connections = $publicize_connections;
161 return true;
162 }
163
164 /**
165 * Add method to update Publicize connections.
166 *
167 * @param array $methods Array of registered methods.
168 * @return array
169 */
170 public function register_update_publicize_connections_xmlrpc_method( $methods ) {
171 return array_merge(
172 $methods,
173 array(
174 'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
175 )
176 );
177 }
178
179 /**
180 * Get a list of all connections.
181 *
182 * Google Plus is no longer a functional service, so we remove it from the list.
183 *
184 * @return array
185 */
186 public function get_all_connections() {
187 $this->refresh_connections();
188
189 $connections = $this->current_connections;
190
191 if ( empty( $connections ) ) {
192 $connections = array();
193 }
194
195 if ( isset( $connections['google_plus'] ) ) {
196 unset( $connections['google_plus'] );
197 }
198 return $connections;
199 }
200
201 /**
202 * Get connections for a specific service.
203 *
204 * @param string $service_name 'facebook', 'twitter', etc.
205 * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
206 * @param false|int $_user_id The user ID. Use false (default) for the current user.
207 * @return false|object[]|array[]
208 */
209 public function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
210 if ( false === $_user_id ) {
211 $_user_id = $this->user_id();
212 }
213
214 $connections = $this->get_all_connections();
215 $connections_to_return = array();
216
217 if ( ! empty( $connections ) && is_array( $connections ) ) {
218 if ( ! empty( $connections[ $service_name ] ) ) {
219 foreach ( $connections[ $service_name ] as $id => $connection ) {
220 if ( $this->is_global_connection( $connection ) || $_user_id === (int) $connection['connection_data']['user_id'] ) {
221 $connections_to_return[ $id ] = $connection;
222 }
223 }
224 }
225
226 return $connections_to_return;
227 }
228
229 return false;
230 }
231
232 /**
233 * Get all connections for a specific user.
234 *
235 * @param array $args Arguments to run operations such as force refresh and connection test results.
236 * @return array
237 */
238 public function get_all_connections_for_user( $args = array() ) {
239 if ( ( isset( $args['clear_cache'] ) && $args['clear_cache'] )
240 || ( isset( $args['test_connections'] ) && $args['test_connections'] ) ) {
241 $this->clear_connections_transient();
242 }
243 $connections = $this->get_all_connections();
244
245 $connections_to_return = array();
246 if ( ! empty( $connections ) ) {
247 foreach ( (array) $connections as $service_name => $connections_for_service ) {
248 foreach ( $connections_for_service as $id => $connection ) {
249 $user_id = (int) $connection['connection_data']['user_id'];
250 if ( $user_id === 0 || $this->user_id() === $user_id ) {
251 $connections_to_return[ $service_name ][ $id ] = $connection;
252 }
253 }
254 }
255 }
256
257 return $connections_to_return;
258 }
259
260 /**
261 * To add the connection test results to the connections.
262 *
263 * @param array $connections The Jetpack Social connections.
264
265 * @return array
266 */
267 public function add_connection_test_results( $connections ) {
268 $path = sprintf( '/sites/%d/publicize/connection-test-results', absint( Jetpack_Options::get_option( 'id' ) ) );
269 $response = Client::wpcom_json_api_request_as_user( $path, '2', array(), null, 'wpcom' );
270 $connection_results = json_decode( wp_remote_retrieve_body( $response ), true );
271 $connection_results_map = array();
272
273 foreach ( $connection_results as $connection_result ) {
274 $connection_results_map[ $connection_result['connection_id'] ] = $connection_result['test_success'] ? 'ok' : 'broken';
275 }
276 foreach ( $connections as $key => $connection ) {
277 if ( isset( $connection_results_map[ $connection['connection_id'] ] ) ) {
278 $connections[ $key ]['status'] = $connection_results_map[ $connection['connection_id'] ];
279 }
280 }
281
282 return $connections;
283 }
284
285 /**
286 * Get a connections for a user.
287 *
288 * @param int $connection_id The connection_id.
289
290 * @return array
291 */
292 public function get_connection_for_user( $connection_id ) {
293 foreach ( $this->get_all_connections_for_user() as $connection ) {
294 if ( (int) $connection['connection_id'] === (int) $connection_id ) {
295 return $connection;
296 }
297 }
298 return array();
299 }
300
301 /**
302 * Get the ID of a connection.
303 *
304 * @param array $connection The connection.
305 * @return string
306 */
307 public function get_connection_id( $connection ) {
308 return $connection['connection_data']['id'];
309 }
310
311 /**
312 * Get the unique ID of a connection.
313 *
314 * @param array $connection The connection.
315 * @return string
316 */
317 public function get_connection_unique_id( $connection ) {
318 return $connection['connection_data']['token_id'];
319 }
320
321 /**
322 * Get the meta of a connection.
323 *
324 * @param array $connection The connection.
325 * @return array
326 */
327 public function get_connection_meta( $connection ) {
328 $connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections.
329 return $connection;
330 }
331
332 /**
333 * Show error on settings page if applicable.
334 */
335 public function admin_page_load() {
336 $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
337
338 if ( 'error' === $action ) {
339 add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
340 }
341 }
342
343 /**
344 * Display an error message.
345 */
346 public function display_connection_error() {
347 $code = false;
348 // phpcs:disable WordPress.Security.NonceVerification.Recommended
349 $service = isset( $_GET['service'] ) ? sanitize_text_field( wp_unslash( $_GET['service'] ) ) : null;
350 $publicize_error = isset( $_GET['publicize_error'] ) ? sanitize_text_field( wp_unslash( $_GET['publicize_error'] ) ) : null;
351 // phpcs:enable WordPress.Security.NonceVerification.Recommended
352
353 if ( $service ) {
354 /* translators: %s is the name of the Jetpack Social service (e.g. Facebook, Twitter) */
355 $error = sprintf( __( 'There was a problem connecting to %s to create an authorized connection. Please try again in a moment.', 'jetpack-publicize-pkg' ), self::get_service_label( $service ) );
356 } elseif ( $publicize_error ) {
357 $code = strtolower( $publicize_error );
358 switch ( $code ) {
359 case '400':
360 $error = __( 'An invalid request was made. This normally means that something intercepted or corrupted the request from your server to the Jetpack Server. Try again and see if it works this time.', 'jetpack-publicize-pkg' );
361 break;
362 case 'secret_mismatch':
363 $error = __( 'We could not verify that your server is making an authorized request. Please try again, and make sure there is nothing interfering with requests from your server to the Jetpack Server.', 'jetpack-publicize-pkg' );
364 break;
365 case 'empty_blog_id':
366 $error = __( 'No blog_id was included in your request. Please try disconnecting Jetpack from WordPress.com and then reconnecting it. Once you have done that, try connecting Jetpack Social again.', 'jetpack-publicize-pkg' );
367 break;
368 case 'empty_state':
369 /* translators: %s is the URL of the Jetpack admin page */
370 $error = sprintf( __( 'No user information was included in your request. Please make sure that your user account has connected to Jetpack. Connect your user account by going to the <a href="%s">Jetpack page</a> within wp-admin.', 'jetpack-publicize-pkg' ), \Jetpack::admin_url() );
371 break;
372 default:
373 $error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack-publicize-pkg' );
374 break;
375 }
376 } else {
377 $error = __( 'There was a problem connecting with Jetpack Social. Please try again in a moment.', 'jetpack-publicize-pkg' );
378 }
379 // Using the same formatting/style as Jetpack::admin_notices() error.
380 ?>
381 <div id="message" class="jetpack-message jetpack-err">
382 <div class="squeezer">
383 <h2>
384 <?php
385 echo wp_kses(
386 $error,
387 array(
388 'a' => array(
389 'href' => true,
390 ),
391 'code' => true,
392 'strong' => true,
393 'br' => true,
394 'b' => true,
395 )
396 );
397 ?>
398 </h2>
399 <?php if ( $code ) : ?>
400 <p>
401 <?php
402 printf(
403 /* translators: %s is the name of the error */
404 esc_html__( 'Error code: %s', 'jetpack-publicize-pkg' ),
405 esc_html( stripslashes( $code ) )
406 );
407 ?>
408 </p>
409 <?php endif; ?>
410 </div>
411 </div>
412 <?php
413 }
414
415 /**
416 * Show a message that the connection has been removed.
417 */
418 public function display_disconnected() {
419 echo "<div class='updated'>\n";
420 echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack-publicize-pkg' ) ) . "</p>\n";
421 echo "</div>\n\n";
422 }
423
424 /**
425 * If applicable, globalize a connection.
426 *
427 * @param string $connection_id Connection ID.
428 */
429 public function globalization( $connection_id ) {
430 if ( isset( $_REQUEST['global'] ) && 'on' === $_REQUEST['global'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce check happens earlier in the process before we get here
431 if ( ! current_user_can( $this->GLOBAL_CAP ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
432 return;
433 }
434
435 $this->globalize_connection( $connection_id );
436 }
437 }
438
439 /**
440 * Globalize a connection.
441 *
442 * @param string $connection_id Connection ID.
443 */
444 public function globalize_connection( $connection_id ) {
445 $xml = new Jetpack_IXR_Client();
446 $xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'globalize' );
447
448 if ( ! $xml->isError() ) {
449 $response = $xml->getResponse();
450 $this->receive_updated_publicize_connections( $response );
451 }
452 }
453
454 /**
455 * Unglobalize a connection.
456 *
457 * @param string $connection_id Connection ID.
458 */
459 public function unglobalize_connection( $connection_id ) {
460 $xml = new Jetpack_IXR_Client();
461 $xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'unglobalize' );
462
463 if ( ! $xml->isError() ) {
464 $response = $xml->getResponse();
465 $this->receive_updated_publicize_connections( $response );
466 }
467 }
468
469 /**
470 * Grabs a fresh copy of the publicize connections data, if the cache is busted.
471 */
472 public function refresh_connections() {
473 if ( null !== $this->current_connections ) {
474 return;
475 }
476
477 $connections = get_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT );
478 if ( false === $connections ) {
479 $xml = new Jetpack_IXR_Client();
480 $xml->query( 'jetpack.fetchPublicizeConnections' );
481 if ( ! $xml->isError() ) {
482 $response = $xml->getResponse();
483 $this->receive_updated_publicize_connections( $response );
484 }
485 return;
486 }
487 $this->current_connections = $connections;
488 }
489
490 /**
491 * Delete the transient.
492 */
493 public function clear_connections_transient() {
494 delete_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT );
495 }
496
497 /**
498 * Get the Publicize connect URL from Keyring.
499 *
500 * @param string $service_name Name of the service to get connect URL for.
501 * @param string $for What the URL is for. Default 'publicize'.
502 * @return string
503 */
504 public function connect_url( $service_name, $for = 'publicize' ) {
505 return Keyring_Helper::connect_url( $service_name, $for );
506 }
507
508 /**
509 * Get the Publicize refresh URL from Keyring.
510 *
511 * @param string $service_name Name of the service to get refresh URL for.
512 * @param string $for What the URL is for. Default 'publicize'.
513 * @return string
514 */
515 public function refresh_url( $service_name, $for = 'publicize' ) {
516 return Keyring_Helper::refresh_url( $service_name, $for );
517 }
518
519 /**
520 * Get the Publicize disconnect URL from Keyring.
521 *
522 * @param string $service_name Name of the service to get disconnect URL for.
523 * @param mixed $id ID of the conenction to disconnect.
524 * @return string
525 */
526 public function disconnect_url( $service_name, $id ) {
527 return Keyring_Helper::disconnect_url( $service_name, $id );
528 }
529
530 /**
531 * Get social networks, either all available or only those that the site is connected to.
532 *
533 * @since 0.1.0
534 * @since-jetpack 2.0.0
535 *
536 * @since-jetpack 6.6.0 Removed Path. Service closed October 2018.
537 *
538 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
539 * @param false|int $_blog_id Get services for a specific blog by ID, or set to false for current blog. Default false.
540 * @param false|int $_user_id Get services for a specific user by ID, or set to false for current user. Default false.
541 * @return array List of social networks.
542 */
543 public function get_services( $filter = 'all', $_blog_id = false, $_user_id = false ) {
544 $services = array(
545 'facebook' => array(),
546 'twitter' => array(),
547 'linkedin' => array(),
548 'tumblr' => array(),
549 'mastodon' => array(),
550 'instagram-business' => array(),
551 'nextdoor' => array(),
552 'threads' => array(),
553 'bluesky' => array(),
554 );
555
556 if ( 'all' === $filter ) {
557 return $services;
558 }
559
560 $connected_services = array();
561 foreach ( $services as $service_name => $empty ) {
562 $connections = $this->get_connections( $service_name, $_blog_id, $_user_id );
563 if ( $connections ) {
564 $connected_services[ $service_name ] = $connections;
565 }
566 }
567 return $connected_services;
568 }
569
570 /**
571 * Get a specific connection. Stub.
572 *
573 * @param string $service_name 'facebook', 'twitter', etc.
574 * @param string $connection_id Connection ID.
575 * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
576 * @param false|int $_user_id The user ID. Use false (default) for the current user.
577 * @return void
578 */
579 public function get_connection( $service_name, $connection_id, $_blog_id = false, $_user_id = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
580 // Stub.
581 }
582
583 /**
584 * Flag a post for Publicize after publishing.
585 *
586 * @param string $new_status New status of the post.
587 * @param string $old_status Old status of the post.
588 * @param WP_Post $post Post object.
589 */
590 public function flag_post_for_publicize( $new_status, $old_status, $post ) {
591 if ( ! $post instanceof \WP_Post || ! $this->post_type_is_publicizeable( $post->post_type ) ) {
592 return;
593 }
594
595 $should_publicize = $this->should_submit_post_pre_checks( $post );
596
597 if ( 'publish' === $new_status && 'publish' !== $old_status ) {
598 /**
599 * Determines whether a post being published gets publicized.
600 *
601 * Side-note: Possibly our most alliterative filter name.
602 *
603 * @since 0.1.0 No longer defaults to true. Adds checks to not publicize based on different contexts.
604 * @since-jetpack 4.1.0
605 *
606 * @param bool $should_publicize Should the post be publicized? Default to true.
607 * @param WP_POST $post Current Post object.
608 */
609 $should_publicize = apply_filters( 'publicize_should_publicize_published_post', $should_publicize, $post );
610
611 if ( $should_publicize ) {
612 update_post_meta( $post->ID, $this->PENDING, true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
613 }
614 }
615 }
616
617 /**
618 * Test a connection.
619 *
620 * @param string $service_name Name of the service.
621 * @param array $connection Connection to be tested.
622 */
623 public function test_connection( $service_name, $connection ) {
624 $id = $this->get_connection_id( $connection );
625
626 if ( array_key_exists( $id, $this->test_connection_results ) ) {
627 return $this->test_connection_results[ $id ];
628 }
629
630 $xml = new Jetpack_IXR_Client();
631 $xml->query( 'jetpack.testPublicizeConnection', $id );
632
633 // Bail if all is well.
634 if ( ! $xml->isError() ) {
635 $this->test_connection_results[ $id ] = true;
636 return true;
637 }
638
639 $xml_response = $xml->getResponse();
640 $connection_test_message = $xml_response['faultString'];
641 $connection_error_code = ( empty( $xml_response['faultCode'] ) || ! is_int( $xml_response['faultCode'] ) )
642 ? -1
643 : $xml_response['faultCode'];
644
645 // Set up refresh if the user can.
646 $user_can_refresh = current_user_can( $this->GLOBAL_CAP ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
647 if ( $user_can_refresh ) {
648 /* translators: %s is the name of a social media service */
649 $refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack-publicize-pkg' ), $this->get_service_label( $service_name ) );
650 $refresh_url = $this->refresh_url( $service_name );
651 }
652
653 $error_data = array(
654 'user_can_refresh' => $user_can_refresh,
655 'refresh_text' => $refresh_text ?? null,
656 'refresh_url' => $refresh_url ?? null,
657 );
658
659 $this->test_connection_results[ $id ] = new WP_Error( $connection_error_code, $connection_test_message, $error_data );
660
661 return $this->test_connection_results[ $id ];
662 }
663
664 /**
665 * Checks if post has already been shared by Publicize in the past.
666 *
667 * Jetpack uses two methods:
668 * 1. A POST_DONE . 'all' postmeta flag, or
669 * 2. if the post has already been published.
670 *
671 * @since 0.1.0
672 * @since-jetpack 6.7.0
673 *
674 * @param integer $post_id Optional. Post ID to query connection status for: will use current post if missing.
675 *
676 * @return bool True if post has already been shared by Publicize, false otherwise.
677 */
678 public function post_is_done_sharing( $post_id = null ) {
679 // Defaults to current post if $post_id is null.
680 $post = get_post( $post_id );
681 if ( null === $post ) {
682 return false;
683 }
684
685 return 'publish' === $post->post_status || get_post_meta( $post->ID, $this->POST_DONE . 'all', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
686 }
687
688 /**
689 * Save a flag locally to indicate that this post has already been Publicized via the selected
690 * connections.
691 *
692 * @param int $post_ID Post ID.
693 * @param WP_Post $post Post object.
694 */
695 public function save_publicized( $post_ID, $post = null ) {
696 if ( null === $post ) {
697 return;
698 }
699 // Only do this when a post transitions to being published.
700 // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
701 if ( get_post_meta( $post->ID, $this->PENDING, false ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
702 delete_post_meta( $post->ID, $this->PENDING );
703 update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
704 }
705 // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
706 }
707
708 /**
709 * Set post flags for Publicize.
710 *
711 * @param array $flags List of flags.
712 * @param WP_Post $post Post object.
713 * @return array
714 */
715 public function set_post_flags( $flags, $post ) {
716 $flags['publicize_post'] = false;
717 if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
718 return $flags;
719 }
720
721 $should_publicize = $this->should_submit_post_pre_checks( $post );
722
723 /** This filter is already documented in modules/publicize/publicize-jetpack.php */
724 if ( ! apply_filters( 'publicize_should_publicize_published_post', $should_publicize, $post ) ) {
725 return $flags;
726 }
727
728 $connected_services = $this->get_all_connections();
729
730 if ( empty( $connected_services ) ) {
731 return $flags;
732 }
733
734 $flags['publicize_post'] = true;
735
736 return $flags;
737 }
738 }
739