Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
37.16% covered (danger)
37.16%
68 / 183
16.67% covered (danger)
16.67%
5 / 30
CRAP
0.00% covered (danger)
0.00%
0 / 1
Publicize
37.16% covered (danger)
37.16%
68 / 183
16.67% covered (danger)
16.67%
5 / 30
2286.78
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 add_disconnect_notice
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 force_user_connection
n/a
0 / 0
n/a
0 / 0
1
 admin_page_warning
n/a
0 / 0
n/a
0 / 0
1
 admin_page_load
n/a
0 / 0
n/a
0 / 0
1
 display_connection_error
n/a
0 / 0
n/a
0 / 0
1
 disconnect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 receive_updated_publicize_connections
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
2.06
 filter_usable_connections
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
7
 register_update_publicize_connections_xmlrpc_method
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 get_all_connections
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 get_connections
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
8.05
 get_all_connections_for_user
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
110
 add_connection_test_results
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 get_connection_for_user
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 get_connection_id
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_connection_unique_id
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_connection_meta
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 display_disconnected
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 globalization
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 globalize_connection
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 unglobalize_connection
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 refresh_connections
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 clear_connections_transient
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 connect_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 refresh_url
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 disconnect_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_services
94.74% covered (success)
94.74%
18 / 19
0.00% covered (danger)
0.00%
0 / 1
4.00
 get_connection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 flag_post_for_publicize
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 test_connection
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
42
 post_is_done_sharing
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 save_publicized
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
4.13
 set_post_flags
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * Publicize class.
4 *
5 * @package automattic/jetpack-publicize
6 */
7
8namespace Automattic\Jetpack\Publicize;
9
10use Automattic\Jetpack\Connection\Client;
11use Jetpack_IXR_Client;
12use Jetpack_Options;
13use WP_Error;
14use WP_Post;
15
16/**
17 * Extend the base class with Jetpack-specific functionality.
18 */
19class Publicize extends Publicize_Base {
20
21    const JETPACK_SOCIAL_CONNECTIONS_TRANSIENT = 'jetpack_social_connections';
22
23    /**
24     * Transitory storage of connection testing results.
25     *
26     * @var array
27     */
28    private $test_connection_results = array();
29
30    /**
31     * Property to store the results of fetching the connections.
32     *
33     * @var null|array
34     */
35    private $current_connections = null;
36
37    /**
38     * Add hooks.
39     */
40    public function __construct() {
41        parent::__construct();
42
43        add_filter( 'jetpack_xmlrpc_unauthenticated_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
44
45        add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
46
47        add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 2 );
48
49        add_action( 'connection_disconnected', array( $this, 'add_disconnect_notice' ) );
50    }
51
52    /**
53     * Add a notice when a connection has been disconnected.
54     */
55    public function add_disconnect_notice() {
56        add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
57    }
58
59    /**
60     * Force user connection before showing the Publicize UI.
61     *
62     * @deprecated 0.88.0 Settings > Sharing no longer hosts the Publicize UI.
63     *
64     * @return void
65     */
66    public function force_user_connection() {
67        _deprecated_function( __METHOD__, 'publicize-0.88.0' );
68    }
69
70    /**
71     * Show a warning when Publicize does not have a connection.
72     *
73     * @deprecated 0.88.0 Settings > Sharing no longer hosts the Publicize UI.
74     *
75     * @return void
76     */
77    public function admin_page_warning() {
78        _deprecated_function( __METHOD__, 'publicize-0.88.0' );
79    }
80
81    /**
82     * Show error on settings page if applicable.
83     *
84     * @deprecated 0.88.0 Settings > Sharing no longer hosts connection errors.
85     *
86     * @return void
87     */
88    public function admin_page_load() {
89        _deprecated_function( __METHOD__, 'publicize-0.88.0' );
90    }
91
92    /**
93     * Display an error message.
94     *
95     * @deprecated 0.88.0 Settings > Sharing no longer hosts connection errors.
96     *
97     * @return void
98     */
99    public function display_connection_error() {
100        _deprecated_function( __METHOD__, 'publicize-0.88.0' );
101    }
102
103    /**
104     * Remove a Publicize Connection.
105     *
106     * @param string    $service_name 'facebook', 'twitter', etc.
107     * @param string    $connection_id Connection ID.
108     * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
109     * @param false|int $_user_id The user ID. Use false (default) for the current user.
110     * @param bool      $force_delete Whether to skip permissions checks.
111     * @return false|void False on failure. Void on success.
112     */
113    public function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
114        return Keyring_Helper::disconnect( $service_name, $connection_id, $_blog_id, $_user_id, $force_delete );
115    }
116
117    /**
118     * Set updated Publicize connections in a transient.
119     *
120     * @param mixed $publicize_connections Updated connections.
121     * @return true
122     */
123    public function receive_updated_publicize_connections( $publicize_connections ) {
124
125        $publicize_connections = self::filter_usable_connections( $publicize_connections );
126
127        // Populate the cache with the new data.
128        Connections::get_all( array( 'ignore_cache' => true ) );
129
130        $expiry = 3600 * 4;
131        if ( ! set_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT, $publicize_connections, $expiry ) ) {
132            // If the transient has beeen set in another request, the call to set_transient can fail. If so,
133            // we can delete the transient and try again.
134            $this->clear_connections_transient();
135            set_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT, $publicize_connections, $expiry );
136        }
137        // Regardless of whether the transient is set ok, let's set and use the local property for this request.
138        $this->current_connections = $publicize_connections;
139        return true;
140    }
141
142    /**
143     * Drop connections we cannot attribute to a user.
144     *
145     * A missing user ID reads as "shared with everyone" in is_global_connection(), so such a
146     * connection would be exposed to every user on the site. User ID 0 is a genuine shared
147     * connection and is kept; unknown fields pass through, as WPCOM adds to this payload.
148     *
149     * @param mixed $publicize_connections Connections, keyed by service name.
150     * @return array
151     */
152    private static function filter_usable_connections( $publicize_connections ) {
153        // An empty payload is valid - it means the site has no connections left.
154        if ( ! is_array( $publicize_connections ) ) {
155            return array();
156        }
157
158        $usable_connections = array();
159
160        foreach ( $publicize_connections as $service_name => $connections_for_service ) {
161            if ( ! is_array( $connections_for_service ) ) {
162                continue;
163            }
164
165            foreach ( $connections_for_service as $id => $connection ) {
166                if ( ! isset( $connection['connection_data']['user_id'] ) || ! is_numeric( $connection['connection_data']['user_id'] ) ) {
167                    continue;
168                }
169
170                $usable_connections[ $service_name ][ $id ] = $connection;
171            }
172        }
173
174        return $usable_connections;
175    }
176
177    /**
178     * Add method to update Publicize connections.
179     *
180     * @todo Kept as a fallback for the jetpack/v4/publicize/connections/sync REST endpoint that replaced it; remove after a few releases (CONNECT-446).
181     *
182     * @param array $methods Array of registered methods.
183     * @return array
184     */
185    public function register_update_publicize_connections_xmlrpc_method( $methods ) {
186        return array_merge(
187            $methods,
188            array(
189                'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
190            )
191        );
192    }
193
194    /**
195     * Get a list of all connections.
196     *
197     * Google Plus is no longer a functional service, so we remove it from the list.
198     *
199     * @return array
200     */
201    public function get_all_connections() {
202        $this->refresh_connections();
203
204        $connections = $this->current_connections;
205
206        if ( empty( $connections ) ) {
207            $connections = array();
208        }
209
210        if ( isset( $connections['google_plus'] ) ) {
211            unset( $connections['google_plus'] );
212        }
213        return $connections;
214    }
215
216    /**
217     * Get connections for a specific service.
218     *
219     * @param string    $service_name 'facebook', 'twitter', etc.
220     * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
221     * @param false|int $_user_id The user ID. Use false (default) for the current user.
222     * @return false|object[]|array[]
223     */
224    public function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
225        if ( false === $_user_id ) {
226            $_user_id = $this->user_id();
227        }
228
229        $connections           = $this->get_all_connections();
230        $connections_to_return = array();
231
232        if ( ! empty( $connections ) && is_array( $connections ) ) {
233            if ( ! empty( $connections[ $service_name ] ) ) {
234                foreach ( $connections[ $service_name ] as $id => $connection ) {
235                    if ( $this->is_global_connection( $connection ) || $_user_id === (int) $connection['connection_data']['user_id'] ) {
236                        $connections_to_return[ $id ] = $connection;
237                    }
238                }
239            }
240
241            return $connections_to_return;
242        }
243
244        return false;
245    }
246
247    /**
248     * Get all connections for a specific user.
249     *
250     * @param array $args Arguments to run operations such as force refresh and connection test results.
251     * @return array
252     */
253    public function get_all_connections_for_user( $args = array() ) {
254        if ( ( isset( $args['clear_cache'] ) && $args['clear_cache'] )
255        || ( isset( $args['test_connections'] ) && $args['test_connections'] ) ) {
256            $this->clear_connections_transient();
257        }
258        $connections = $this->get_all_connections();
259
260        $connections_to_return = array();
261        if ( ! empty( $connections ) ) {
262            foreach ( (array) $connections as $service_name => $connections_for_service ) {
263                foreach ( $connections_for_service as $id => $connection ) {
264                    $user_id = (int) $connection['connection_data']['user_id'];
265                    if ( $user_id === 0 || $this->user_id() === $user_id ) {
266                        $connections_to_return[ $service_name ][ $id ] = $connection;
267                    }
268                }
269            }
270        }
271
272        return $connections_to_return;
273    }
274
275    /**
276     * To add the connection test results to the connections.
277     *
278     * @param array $connections The Jetpack Social connections.
279
280     * @return array
281     */
282    public function add_connection_test_results( $connections ) {
283        $path                   = sprintf( '/sites/%d/publicize/connection-test-results', absint( Jetpack_Options::get_option( 'id' ) ) );
284        $response               = Client::wpcom_json_api_request_as_user( $path, '2', array(), null, 'wpcom' );
285        $connection_results     = json_decode( wp_remote_retrieve_body( $response ), true );
286        $connection_results_map = array();
287
288        foreach ( $connection_results as $connection_result ) {
289            $connection_results_map[ $connection_result['connection_id'] ] = $connection_result['test_success'] ? 'ok' : 'broken';
290        }
291        foreach ( $connections as $key => $connection ) {
292            if ( isset( $connection_results_map[ $connection['connection_id'] ] ) ) {
293                $connections[ $key ]['status'] = $connection_results_map[ $connection['connection_id'] ];
294            }
295        }
296
297        return $connections;
298    }
299
300    /**
301     * Get a connections for a user.
302     *
303     * @param int $connection_id The connection_id.
304
305     * @return array
306     */
307    public function get_connection_for_user( $connection_id ) {
308        foreach ( $this->get_all_connections_for_user() as $connection ) {
309            if ( (int) $connection['connection_id'] === (int) $connection_id ) {
310                return $connection;
311            }
312        }
313        return array();
314    }
315
316    /**
317     * Get the ID of a connection.
318     *
319     * @param array $connection The connection.
320     * @return string
321     */
322    public function get_connection_id( $connection ) {
323        return $connection['connection_data']['id'];
324    }
325
326    /**
327     * Get the unique ID of a connection.
328     *
329     * @param array $connection The connection.
330     * @return string
331     */
332    public function get_connection_unique_id( $connection ) {
333        return $connection['connection_data']['token_id'];
334    }
335
336    /**
337     * Get the meta of a connection.
338     *
339     * @param array $connection The connection.
340     * @return array
341     */
342    public function get_connection_meta( $connection ) {
343        $connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections.
344        return $connection;
345    }
346
347    /**
348     * Show a message that the connection has been removed.
349     */
350    public function display_disconnected() {
351        echo "<div class='updated'>\n";
352        echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack-publicize-pkg' ) ) . "</p>\n";
353        echo "</div>\n\n";
354    }
355
356    /**
357     * If applicable, globalize a connection.
358     *
359     * @param string $connection_id Connection ID.
360     */
361    public function globalization( $connection_id ) {
362        if ( isset( $_REQUEST['global'] ) && 'on' === $_REQUEST['global'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce check happens earlier in the process before we get here
363            if ( ! current_user_can( $this->GLOBAL_CAP ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
364                return;
365            }
366
367            $this->globalize_connection( $connection_id );
368        }
369    }
370
371    /**
372     * Globalize a connection.
373     *
374     * @param string $connection_id Connection ID.
375     */
376    public function globalize_connection( $connection_id ) {
377        $xml = new Jetpack_IXR_Client();
378        $xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'globalize' );
379
380        if ( ! $xml->isError() ) {
381            $response = $xml->getResponse();
382            $this->receive_updated_publicize_connections( $response );
383        }
384    }
385
386    /**
387     * Unglobalize a connection.
388     *
389     * @param string $connection_id Connection ID.
390     */
391    public function unglobalize_connection( $connection_id ) {
392        $xml = new Jetpack_IXR_Client();
393        $xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'unglobalize' );
394
395        if ( ! $xml->isError() ) {
396            $response = $xml->getResponse();
397            $this->receive_updated_publicize_connections( $response );
398        }
399    }
400
401    /**
402     * Grabs a fresh copy of the publicize connections data, if the cache is busted.
403     */
404    public function refresh_connections() {
405        if ( null !== $this->current_connections ) {
406            return;
407        }
408
409        $connections = get_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT );
410        if ( false === $connections ) {
411            $xml = new Jetpack_IXR_Client();
412            $xml->query( 'jetpack.fetchPublicizeConnections' );
413            if ( ! $xml->isError() ) {
414                $response = $xml->getResponse();
415                $this->receive_updated_publicize_connections( $response );
416            }
417            return;
418        }
419        $this->current_connections = $connections;
420    }
421
422    /**
423     * Delete the transient.
424     */
425    public function clear_connections_transient() {
426        delete_transient( self::JETPACK_SOCIAL_CONNECTIONS_TRANSIENT );
427    }
428
429    /**
430     * Get the Publicize connect URL from Keyring.
431     *
432     * @param string $service_name Name of the service to get connect URL for.
433     * @param string $for What the URL is for. Default 'publicize'.
434     * @return string
435     */
436    public function connect_url( $service_name, $for = 'publicize' ) {
437        return Keyring_Helper::connect_url( $service_name, $for );
438    }
439
440    /**
441     * Get the Publicize refresh URL from Keyring.
442     *
443     * @param string $service_name Name of the service to get refresh URL for.
444     * @param string $for What the URL is for. Default 'publicize'.
445     * @return string
446     */
447    public function refresh_url( $service_name, $for = 'publicize' ) {
448        return Keyring_Helper::refresh_url( $service_name, $for );
449    }
450
451    /**
452     * Get the Publicize disconnect URL from Keyring.
453     *
454     * @param string $service_name Name of the service to get disconnect URL for.
455     * @param mixed  $id ID of the conenction to disconnect.
456     * @return string
457     */
458    public function disconnect_url( $service_name, $id ) {
459        return Keyring_Helper::disconnect_url( $service_name, $id );
460    }
461
462    /**
463     * Get social networks, either all available or only those that the site is connected to.
464     *
465     * @since 0.1.0
466     * @since-jetpack 2.0.0
467     *
468     * @since-jetpack 6.6.0 Removed Path. Service closed October 2018.
469     *
470     * @param string    $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
471     * @param false|int $_blog_id Get services for a specific blog by ID, or set to false for current blog. Default false.
472     * @param false|int $_user_id Get services for a specific user by ID, or set to false for current user. Default false.
473     * @return array List of social networks.
474     */
475    public function get_services( $filter = 'all', $_blog_id = false, $_user_id = false ) {
476        $services = array(
477            'facebook'           => array(),
478            'twitter'            => array(),
479            'linkedin'           => array(),
480            'tumblr'             => array(),
481            'mastodon'           => array(),
482            'instagram-business' => array(),
483            'nextdoor'           => array(),
484            'threads'            => array(),
485            'bluesky'            => array(),
486        );
487
488        if ( 'all' === $filter ) {
489            return $services;
490        }
491
492        $connected_services = array();
493        foreach ( $services as $service_name => $empty ) {
494            $connections = $this->get_connections( $service_name, $_blog_id, $_user_id );
495            if ( $connections ) {
496                $connected_services[ $service_name ] = $connections;
497            }
498        }
499        return $connected_services;
500    }
501
502    /**
503     * Get a specific connection. Stub.
504     *
505     * @param string    $service_name 'facebook', 'twitter', etc.
506     * @param string    $connection_id Connection ID.
507     * @param false|int $_blog_id The blog ID. Use false (default) for the current blog.
508     * @param false|int $_user_id The user ID. Use false (default) for the current user.
509     * @return void
510     */
511    public function get_connection( $service_name, $connection_id, $_blog_id = false, $_user_id = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
512        // Stub.
513    }
514
515    /**
516     * Flag a post for Publicize after publishing.
517     *
518     * @param string  $new_status New status of the post.
519     * @param string  $old_status Old status of the post.
520     * @param WP_Post $post Post object.
521     */
522    public function flag_post_for_publicize( $new_status, $old_status, $post ) {
523        if ( ! $post instanceof \WP_Post || ! $this->post_type_is_publicizeable( $post->post_type ) ) {
524            return;
525        }
526
527        $should_publicize = $this->should_submit_post_pre_checks( $post );
528
529        if ( 'publish' === $new_status && 'publish' !== $old_status ) {
530            /**
531             * Determines whether a post being published gets publicized.
532             *
533             * Side-note: Possibly our most alliterative filter name.
534             *
535             * @since 0.1.0 No longer defaults to true. Adds checks to not publicize based on different contexts.
536             * @since-jetpack 4.1.0
537             *
538             * @param bool $should_publicize Should the post be publicized? Default to true.
539             * @param WP_POST $post Current Post object.
540             */
541            $should_publicize = apply_filters( 'publicize_should_publicize_published_post', $should_publicize, $post );
542
543            if ( $should_publicize ) {
544                update_post_meta( $post->ID, $this->PENDING, true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
545            }
546        }
547    }
548
549    /**
550     * Test a connection.
551     *
552     * @param string $service_name Name of the service.
553     * @param array  $connection Connection to be tested.
554     */
555    public function test_connection( $service_name, $connection ) {
556        $id = $this->get_connection_id( $connection );
557
558        if ( array_key_exists( $id, $this->test_connection_results ) ) {
559            return $this->test_connection_results[ $id ];
560        }
561
562        $xml = new Jetpack_IXR_Client();
563        $xml->query( 'jetpack.testPublicizeConnection', $id );
564
565        // Bail if all is well.
566        if ( ! $xml->isError() ) {
567            $this->test_connection_results[ $id ] = true;
568            return true;
569        }
570
571        $xml_response            = $xml->getResponse();
572        $connection_test_message = $xml_response['faultString'];
573        $connection_error_code   = ( empty( $xml_response['faultCode'] ) || ! is_int( $xml_response['faultCode'] ) )
574            ? -1
575            : $xml_response['faultCode'];
576
577        // Set up refresh if the user can.
578        $user_can_refresh = current_user_can( $this->GLOBAL_CAP ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
579        if ( $user_can_refresh ) {
580            /* translators: %s is the name of a social media service */
581            $refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack-publicize-pkg' ), $this->get_service_label( $service_name ) );
582            $refresh_url  = $this->refresh_url( $service_name );
583        }
584
585        $error_data = array(
586            'user_can_refresh' => $user_can_refresh,
587            'refresh_text'     => $refresh_text ?? null,
588            'refresh_url'      => $refresh_url ?? null,
589        );
590
591        $this->test_connection_results[ $id ] = new WP_Error( $connection_error_code, $connection_test_message, $error_data );
592
593        return $this->test_connection_results[ $id ];
594    }
595
596    /**
597     * Checks if post has already been shared by Publicize in the past.
598     *
599     * Jetpack uses two methods:
600     * 1. A POST_DONE . 'all' postmeta flag, or
601     * 2. if the post has already been published.
602     *
603     * @since 0.1.0
604     * @since-jetpack 6.7.0
605     *
606     * @param integer $post_id Optional. Post ID to query connection status for: will use current post if missing.
607     *
608     * @return bool True if post has already been shared by Publicize, false otherwise.
609     */
610    public function post_is_done_sharing( $post_id = null ) {
611        // Defaults to current post if $post_id is null.
612        $post = get_post( $post_id );
613        if ( null === $post ) {
614            return false;
615        }
616
617        return 'publish' === $post->post_status || get_post_meta( $post->ID, $this->POST_DONE . 'all', true ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
618    }
619
620    /**
621     * Save a flag locally to indicate that this post has already been Publicized via the selected
622     * connections.
623     *
624     * @param int     $post_ID Post ID.
625     * @param WP_Post $post Post object.
626     */
627    public function save_publicized( $post_ID, $post = null ) {
628        if ( null === $post ) {
629            return;
630        }
631        // Only do this when a post transitions to being published.
632        // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
633        if ( get_post_meta( $post->ID, $this->PENDING, false ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
634            delete_post_meta( $post->ID, $this->PENDING );
635            update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
636        }
637        // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
638    }
639
640    /**
641     * Set post flags for Publicize.
642     *
643     * @param array   $flags List of flags.
644     * @param WP_Post $post Post object.
645     * @return array
646     */
647    public function set_post_flags( $flags, $post ) {
648        $flags['publicize_post'] = false;
649        if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
650            return $flags;
651        }
652
653        $should_publicize = $this->should_submit_post_pre_checks( $post );
654
655        /** This filter is already documented in modules/publicize/publicize-jetpack.php */
656        if ( ! apply_filters( 'publicize_should_publicize_published_post', $should_publicize, $post ) ) {
657            return $flags;
658        }
659
660        $connected_services = $this->get_all_connections();
661
662        if ( empty( $connected_services ) ) {
663            return $flags;
664        }
665
666        $flags['publicize_post'] = true;
667
668        return $flags;
669    }
670}