Completed
Push — update/editor-blocks-icon-colo... ( 093ab2...3cfb5e )
by
unknown
08:47
created

Publicize::set_post_flags()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 2
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Redirect;
4
5
class Publicize extends Publicize_Base {
6
7
	function __construct() {
8
		parent::__construct();
9
10
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
11
12
		add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
13
14
		add_action( 'wp_ajax_publicize_tumblr_options_page', array( $this, 'options_page_tumblr' ) );
15
		add_action( 'wp_ajax_publicize_facebook_options_page', array( $this, 'options_page_facebook' ) );
16
		add_action( 'wp_ajax_publicize_twitter_options_page', array( $this, 'options_page_twitter' ) );
17
		add_action( 'wp_ajax_publicize_linkedin_options_page', array( $this, 'options_page_linkedin' ) );
18
19
		add_action( 'wp_ajax_publicize_tumblr_options_save', array( $this, 'options_save_tumblr' ) );
20
		add_action( 'wp_ajax_publicize_facebook_options_save', array( $this, 'options_save_facebook' ) );
21
		add_action( 'wp_ajax_publicize_twitter_options_save', array( $this, 'options_save_twitter' ) );
22
		add_action( 'wp_ajax_publicize_linkedin_options_save', array( $this, 'options_save_linkedin' ) );
23
24
		add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
25
26
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
27
28
		add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 3 );
29
30
		add_filter( 'jetpack_twitter_cards_site_tag', array( $this, 'enhaced_twitter_cards_site_tag' ) );
31
32
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_twitter_account' ), 10, 4 );
33
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_facebook_account' ), 10, 4 );
34
35
		add_action( 'connection_disconnected', array( $this, 'add_disconnect_notice' ) );
36
37
		add_filter( 'jetpack_sharing_twitter_via', array( $this, 'get_publicized_twitter_account' ), 10, 2 );
38
39
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
40
41
		jetpack_require_lib( 'class.jetpack-keyring-service-helper' );
42
	}
43
44
	function add_disconnect_notice() {
45
		add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
46
	}
47
48
	function force_user_connection() {
49
		global $current_user;
50
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack_Data::get_access_token() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
51
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
52
53
		// If the user is already connected via Jetpack, then we're good
54
		if ( $is_user_connected ) {
55
			return;
56
		}
57
58
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
59
		global $publicize_ui;
60
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
61
62
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
63
		// Jetpack::init()->admin_styles();
64
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
65
	}
66
67
	function admin_page_warning() {
68
		$jetpack   = Jetpack::init();
69
		$blog_name = get_bloginfo( 'blogname' );
70
		if ( empty( $blog_name ) ) {
71
			$blog_name = home_url( '/' );
72
		}
73
74
		?>
75
		<div id="message" class="updated jetpack-message jp-connect">
76
			<div class="jetpack-wrap-container">
77
				<div class="jetpack-text-container">
78
					<p><?php printf(
79
							/* translators: %s is the name of the blog */
80
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
81
							'<strong>' . esc_html( $blog_name ) . '</strong>'
82
						); ?></p>
83
					<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' ) ) ); ?></p>
84
				</div>
85
				<div class="jetpack-install-container">
86
					<p class="submit"><a
87
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
88
							class="button-connector"
89
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
90
					</p>
91
					<p class="jetpack-install-blurb">
92
						<?php jetpack_render_tos_blurb(); ?>
93
					</p>
94
				</div>
95
			</div>
96
		</div>
97
		<?php
98
	}
99
100
	/**
101
	 * Remove a Publicize connection
102
	 */
103
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
104
		return Jetpack_Keyring_Service_Helper::disconnect( $service_name, $connection_id, $_blog_id, $_user_id, $force_delete );
105
	}
106
107
	function receive_updated_publicize_connections( $publicize_connections ) {
108
		Jetpack_Options::update_option( 'publicize_connections', $publicize_connections );
109
110
		return true;
111
	}
112
113
	function register_update_publicize_connections_xmlrpc_method( $methods ) {
114
		return array_merge( $methods, array(
115
			'jetpack.updatePublicizeConnections' => array( $this, 'receive_updated_publicize_connections' ),
116
		) );
117
	}
118
119
	function get_all_connections() {
120
		$connections = Jetpack_Options::get_option( 'publicize_connections' );
121
		if ( isset( $connections['google_plus'] ) ) {
122
			unset( $connections['google_plus'] );
123
		}
124
		return $connections;
125
	}
126
127
	function get_connections( $service_name, $_blog_id = false, $_user_id = false ) {
128
		if ( false === $_user_id ) {
129
			$_user_id = $this->user_id();
130
		}
131
132
		$connections           = $this->get_all_connections();
133
		$connections_to_return = array();
134
135
		if ( ! empty( $connections ) && is_array( $connections ) ) {
136
			if ( ! empty( $connections[ $service_name ] ) ) {
137
				foreach ( $connections[ $service_name ] as $id => $connection ) {
138
					if ( 0 == $connection['connection_data']['user_id'] || $_user_id == $connection['connection_data']['user_id'] ) {
139
						$connections_to_return[ $id ] = $connection;
140
					}
141
				}
142
			}
143
144
			return $connections_to_return;
145
		}
146
147
		return false;
148
	}
149
150
	function get_all_connections_for_user() {
151
		$connections = $this->get_all_connections();
152
153
		$connections_to_return = array();
154
		if ( ! empty( $connections ) ) {
155
			foreach ( (array) $connections as $service_name => $connections_for_service ) {
156
				foreach ( $connections_for_service as $id => $connection ) {
157
					$user_id = intval( $connection['connection_data']['user_id'] );
158
					// phpcs:ignore WordPress.PHP.YodaConditions.NotYoda
159
					if ( $user_id === 0 || $this->user_id() === $user_id ) {
160
						$connections_to_return[ $service_name ][ $id ] = $connection;
161
					}
162
				}
163
			}
164
165
			return $connections_to_return;
166
		}
167
168
		return false;
169
	}
170
171
	function get_connection_id( $connection ) {
172
		return $connection['connection_data']['id'];
173
	}
174
175
	function get_connection_unique_id( $connection ) {
176
		return $connection['connection_data']['token_id'];
177
	}
178
179
	function get_connection_meta( $connection ) {
180
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
181
		return $connection;
182
	}
183
184
	function admin_page_load() {
185
		if ( isset( $_GET['action'] ) && 'error' === $_GET['action'] ) {
186
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
187
		}
188
	}
189
190
	function display_connection_error() {
191
		$code = false;
192
		if ( isset( $_GET['service'] ) ) {
193
			$service_name = $_GET['service'];
194
			$error        = sprintf( __( 'There was a problem connecting to %s to create an authorized connection. Please try again in a moment.', 'jetpack' ), Publicize::get_service_label( $service_name ) );
195
		} else {
196
			if ( isset( $_GET['publicize_error'] ) ) {
197
				$code = strtolower( $_GET['publicize_error'] );
198
				switch ( $code ) {
199
					case '400':
200
						$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' );
201
						break;
202
					case 'secret_mismatch':
203
						$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' );
204
						break;
205
					case 'empty_blog_id':
206
						$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 Publicize again.', 'jetpack' );
207
						break;
208
					case 'empty_state':
209
						$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' ), Jetpack::admin_url() );
210
						break;
211
					default:
212
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
213
						break;
214
				}
215
			} else {
216
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
217
			}
218
		}
219
		// Using the same formatting/style as Jetpack::admin_notices() error
220
		?>
221
		<div id="message" class="jetpack-message jetpack-err">
222
			<div class="squeezer">
223
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
224
				                                       'code'   => true,
225
				                                       'strong' => true,
226
				                                       'br'     => true,
227
				                                       'b'      => true
228
					) ); ?></h2>
229
				<?php if ( $code ) : ?>
0 ignored issues
show
Bug Best Practice introduced by
The expression $code of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
230
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
231
				<?php endif; ?>
232
			</div>
233
		</div>
234
		<?php
235
	}
236
237
	function display_disconnected() {
238
		echo "<div class='updated'>\n";
239
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
240
		echo "</div>\n\n";
241
	}
242
243
	function globalization() {
244
		if ( 'on' == $_REQUEST['global'] ) {
245
			$globalize_connection = $_REQUEST['connection'];
246
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
247
				return;
248
			}
249
250
			$this->globalize_connection( $globalize_connection );
251
		}
252
	}
253
254 View Code Duplication
	function globalize_connection( $connection_id ) {
255
		$xml = new Jetpack_IXR_Client();
256
		$xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'globalize' );
257
258
		if ( ! $xml->isError() ) {
259
			$response = $xml->getResponse();
260
			$this->receive_updated_publicize_connections( $response );
261
		}
262
	}
263
264 View Code Duplication
	function unglobalize_connection( $connection_id ) {
265
		$xml = new Jetpack_IXR_Client();
266
		$xml->query( 'jetpack.globalizePublicizeConnection', $connection_id, 'unglobalize' );
267
268
		if ( ! $xml->isError() ) {
269
			$response = $xml->getResponse();
270
			$this->receive_updated_publicize_connections( $response );
271
		}
272
	}
273
274
	function connect_url( $service_name, $for = 'publicize' ) {
275
		return Jetpack_Keyring_Service_Helper::connect_url( $service_name, $for );
276
	}
277
278
	function refresh_url( $service_name, $for = 'publicize' ) {
279
		return Jetpack_Keyring_Service_Helper::refresh_url( $service_name, $for );
280
	}
281
282
	function disconnect_url( $service_name, $id ) {
283
		return Jetpack_Keyring_Service_Helper::disconnect_url( $service_name, $id );
284
	}
285
286
	/**
287
	 * Get social networks, either all available or only those that the site is connected to.
288
	 *
289
	 * @since 2.0.0
290
	 * @since 6.6.0 Removed Path. Service closed October 2018.
291
	 *
292
	 * @param string $filter Select the list of services that will be returned. Defaults to 'all', accepts 'connected'.
293
	 *
294
	 * @return array List of social networks.
295
	 */
296
	function get_services( $filter = 'all', $_blog_id = false, $_user_id = false ) {
297
		$services = array(
298
			'facebook'    => array(),
299
			'twitter'     => array(),
300
			'linkedin'    => array(),
301
			'tumblr'      => array(),
302
		);
303
304 View Code Duplication
		if ( 'all' == $filter ) {
305
			return $services;
306
		} else {
307
			$connected_services = array();
308
			foreach ( $services as $service_name => $empty ) {
309
				$connections = $this->get_connections( $service_name, $_blog_id, $_user_id );
310
				if ( $connections ) {
311
					$connected_services[ $service_name ] = $connections;
312
				}
313
			}
314
			return $connected_services;
315
		}
316
	}
317
318
	function get_connection( $service_name, $id, $_blog_id = false, $_user_id = false ) {
319
		// Stub
320
	}
321
322
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
323
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
324
			return;
325
		}
326
327
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
328
			/**
329
			 * Determines whether a post being published gets publicized.
330
			 *
331
			 * Side-note: Possibly our most alliterative filter name.
332
			 *
333
			 * @module publicize
334
			 *
335
			 * @since 4.1.0
336
			 *
337
			 * @param bool $should_publicize Should the post be publicized? Default to true.
338
			 * @param WP_POST $post Current Post object.
339
			 */
340
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $post.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
341
342
			if ( $should_publicize ) {
343
				update_post_meta( $post->ID, $this->PENDING, true );
344
			}
345
		}
346
	}
347
348
	function test_connection( $service_name, $connection ) {
349
350
		$id = $this->get_connection_id( $connection );
351
352
		$xml = new Jetpack_IXR_Client();
353
		$xml->query( 'jetpack.testPublicizeConnection', $id );
354
355
		// Bail if all is well
356
		if ( ! $xml->isError() ) {
357
			return true;
358
		}
359
360
		$xml_response            = $xml->getResponse();
361
		$connection_test_message = $xml_response['faultString'];
362
363
		// Set up refresh if the user can
364
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
365
		if ( $user_can_refresh ) {
366
			$nonce        = wp_create_nonce( "keyring-request-" . $service_name );
0 ignored issues
show
Unused Code introduced by
$nonce is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
367
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
368
			$refresh_url  = $this->refresh_url( $service_name );
369
		}
370
371
		$error_data = array(
372
			'user_can_refresh' => $user_can_refresh,
373
			'refresh_text'     => $refresh_text,
0 ignored issues
show
Bug introduced by
The variable $refresh_text does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
374
			'refresh_url'      => $refresh_url
0 ignored issues
show
Bug introduced by
The variable $refresh_url does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
375
		);
376
377
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'pub_conn_test_failed'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
378
	}
379
380
	/**
381
	 * Checks if post has already been shared by Publicize in the past.
382
	 *
383
	 * Jetpack uses two methods:
384
	 * 1. A POST_DONE . 'all' postmeta flag, or
385
	 * 2. if the post has already been published.
386
	 *
387
	 * @since 6.7.0
388
	 *
389
	 * @param integer $post_id Optional. Post ID to query connection status for: will use current post if missing.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $post_id not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
390
	 *
391
	 * @return bool True if post has already been shared by Publicize, false otherwise.
392
	 */
393
	public function post_is_done_sharing( $post_id = null ) {
394
		// Defaults to current post if $post_id is null.
395
		$post = get_post( $post_id );
396
		if ( is_null( $post ) ) {
397
			return false;
398
		}
399
400
		return 'publish' == $post->post_status || get_post_meta( $post->ID, $this->POST_DONE . 'all', true );
401
	}
402
403
	/**
404
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
405
	 * connections.
406
	 */
407
	function save_publicized( $post_ID, $post = null, $update = null ) {
408
		if ( is_null( $post ) ) {
409
			return;
410
		}
411
		// Only do this when a post transitions to being published
412
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
413
			$connected_services = $this->get_all_connections();
414
			if ( ! empty( $connected_services ) ) {
415
				/**
416
				 * Fires when a post is saved that has is marked as pending publicizing
417
				 *
418
				 * @since 4.1.0
419
				 *
420
				 * @param int The post ID
421
				 */
422
				do_action_deprecated( 'jetpack_publicize_post', $post->ID, '4.8.0', 'jetpack_published_post_flags' );
423
			}
424
			delete_post_meta( $post->ID, $this->PENDING );
425
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
426
		}
427
	}
428
429
	function set_post_flags( $flags, $post ) {
430
		$flags['publicize_post'] = false;
431
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
432
			return $flags;
433
		}
434
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
435
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $post.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
436
			return $flags;
437
		}
438
439
		$connected_services = $this->get_all_connections();
440
441
		if ( empty( $connected_services ) ) {
442
			return $flags;
443
		}
444
445
		$flags['publicize_post'] = true;
446
447
		return $flags;
448
	}
449
450
	/**
451
	 * Options Code
452
	 */
453
454
	function options_page_facebook() {
455
		$connected_services = $this->get_all_connections();
456
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
457
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
458
459
		// Nonce check
460
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
461
462
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
463
464
		$page_selected   = false;
465
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
466
			$found = false;
467
			if ( $pages && isset( $pages->data ) && is_array( $pages->data )  ) {
468
				foreach ( $pages->data as $page ) {
469
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
470
						$found = true;
471
						break;
472
					}
473
				}
474
			}
475
476
			if ( $found ) {
477
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
478
			}
479
		}
480
481
		?>
482
483
		<div id="thickbox-content">
484
485
			<?php
486
			ob_start();
487
			Publicize_UI::connected_notice( 'Facebook' );
0 ignored issues
show
Bug introduced by
The method connected_notice() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
488
			$update_notice = ob_get_clean();
489
490
			if ( ! empty( $update_notice ) ) {
491
				echo $update_notice;
492
			}
493
			$page_info_message = sprintf(
494
				__( 'Facebook supports Publicize connections to Facebook Pages, but not to Facebook Profiles. <a href="%s">Learn More about Publicize for Facebook</a>', 'jetpack' ),
495
				esc_url( Redirect::get_url( 'jetpack-support-publicize-facebook' ) )
496
			);
497
498
			if ( $pages ) : ?>
499
				<p><?php _e( 'Publicize to my <strong>Facebook Page</strong>:', 'jetpack' ); ?></p>
500
				<table id="option-fb-fanpage">
501
					<tbody>
502
503
					<?php foreach ( $pages as $i => $page ) : ?>
504
						<?php if ( ! ( $i % 2 ) ) : ?>
505
							<tr>
506
						<?php endif; ?>
507
						<td class="radio"><input type="radio" name="option" data-type="page"
508
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
509
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
510
						</td>
511
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
512
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
513
									width="50" height="50"/></label></td>
514
						<td class="details">
515
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
516
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
517
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
518
							</label>
519
						</td>
520
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
521
							</tr>
522
						<?php endif; ?>
523
					<?php endforeach; ?>
524
525
					</tbody>
526
				</table>
527
528
				<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
0 ignored issues
show
Bug introduced by
The method global_checkbox() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
529
				<p style="text-align: center;">
530
					<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
531
					       class="button fb-options save-options" name="save"
532
					       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
533
					       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
534
				</p><br/>
535
				<p><?php echo $page_info_message; ?></p>
536
			<?php else: ?>
537
				<div>
538
					<p><?php echo $page_info_message; ?></p>
539
					<p><?php printf( __( '<a class="button" href="%s" target="%s">Create a Facebook page</a> to get started.', 'jetpack' ), 'https://www.facebook.com/pages/creation/', '_blank noopener noreferrer' ); ?></p>
540
				</div>
541
			<?php endif; ?>
542
		</div>
543
		<?php
544
	}
545
546
	function options_save_facebook() {
547
		// Nonce check
548
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
549
550
		// Check for a numeric page ID
551
		$page_id = $_POST['selected_id'];
552
		if ( ! ctype_digit( $page_id ) ) {
553
			die( 'Security check' );
554
		}
555
556
		if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
557
			return;
558
		}
559
560
		// Publish to Page
561
		$options = array(
562
			'facebook_page'    => $page_id,
563
			'facebook_profile' => null
564
		);
565
566
		$this->set_remote_publicize_options( $_POST['connection'], $options );
567
	}
568
569
	function options_page_tumblr() {
570
		// Nonce check
571
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
572
573
		$connected_services = $this->get_all_connections();
574
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
575
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
576
		$request            = $options_to_show[0];
577
578
		$blogs = $request['response']['user']['blogs'];
579
580
		$blog_selected = false;
581
582
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
583
			foreach ( $blogs as $blog ) {
584
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
585
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
586
					break;
587
				}
588
			}
589
590
		}
591
592
		// Use their Primary blog if they haven't selected one yet
593
		if ( ! $blog_selected ) {
594
			foreach ( $blogs as $blog ) {
595
				if ( $blog['primary'] ) {
596
					$blog_selected = $this->get_basehostname( $blog['url'] );
597
				}
598
			}
599
		} ?>
600
601
		<div id="thickbox-content">
602
603
			<?php
604
			ob_start();
605
			Publicize_UI::connected_notice( 'Tumblr' );
0 ignored issues
show
Bug introduced by
The method connected_notice() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
606
			$update_notice = ob_get_clean();
607
608
			if ( ! empty( $update_notice ) ) {
609
				echo $update_notice;
610
			}
611
			?>
612
613
			<p><?php _e( 'Publicize to my <strong>Tumblr blog</strong>:', 'jetpack' ); ?></p>
614
615
			<ul id="option-tumblr-blog">
616
617
				<?php
618
				foreach ( $blogs as $blog ) {
619
					$url = $this->get_basehostname( $blog['url'] ); ?>
620
					<li>
621
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
622
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
623
						<label for="<?php echo esc_attr( $url ) ?>"><span
624
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
625
					</li>
626
				<?php } ?>
627
628
			</ul>
629
630
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
0 ignored issues
show
Bug introduced by
The method global_checkbox() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
631
632
			<p style="text-align: center;">
633
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
634
				       class="button tumblr-options save-options" name="save"
635
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
636
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
637
			</p> <br/>
638
		</div>
639
640
		<?php
641
	}
642
643
	function get_basehostname( $url ) {
644
		return wp_parse_url( $url, PHP_URL_HOST );
0 ignored issues
show
Unused Code introduced by
The call to wp_parse_url() has too many arguments starting with PHP_URL_HOST.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
645
	}
646
647
	function options_save_tumblr() {
648
		// Nonce check
649
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
650
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
651
652
		$this->set_remote_publicize_options( $_POST['connection'], $options );
653
654
	}
655
656
	function set_remote_publicize_options( $id, $options ) {
657
		$xml = new Jetpack_IXR_Client();
658
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
659
660
		if ( ! $xml->isError() ) {
661
			$response = $xml->getResponse();
662
			Jetpack_Options::update_option( 'publicize_connections', $response );
663
			$this->globalization();
664
		}
665
	}
666
667
	function options_page_twitter() {
668
		Publicize_UI::options_page_other( 'twitter' );
0 ignored issues
show
Bug introduced by
The method options_page_other() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
669
	}
670
671
	function options_page_linkedin() {
672
		Publicize_UI::options_page_other( 'linkedin' );
0 ignored issues
show
Bug introduced by
The method options_page_other() does not seem to exist on object<Publicize_UI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
673
	}
674
675
	function options_save_twitter() {
676
		$this->options_save_other( 'twitter' );
677
	}
678
679
	function options_save_linkedin() {
680
		$this->options_save_other( 'linkedin' );
681
	}
682
683
	function options_save_other( $service_name ) {
684
		// Nonce check
685
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
686
		$this->globalization();
687
	}
688
689
	/**
690
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
691
	 */
692
	function enhaced_twitter_cards_site_tag( $tag ) {
693
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
694
		if ( ! empty( $custom_site_tag ) ) {
695
			return $tag;
696
		}
697
		if ( ! $this->is_enabled( 'twitter' ) ) {
698
			return $tag;
699
		}
700
		$connections = $this->get_connections( 'twitter' );
701
		foreach ( $connections as $connection ) {
0 ignored issues
show
Bug introduced by
The expression $connections of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
702
			$connection_meta = $this->get_connection_meta( $connection );
703
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
704
				// If the connection is shared
705
				return $this->get_display_name( 'twitter', $connection );
706
			}
707
		}
708
709
		return $tag;
710
	}
711
712
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
713
		if ( 'twitter' == $service_name && $submit_post ) {
714
			$connection_meta        = $this->get_connection_meta( $connection );
715
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
716
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
717
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
718
			}
719
		}
720
	}
721
722
	function get_publicized_twitter_account( $account, $post_id ) {
723
		if ( ! empty( $account ) ) {
724
			return $account;
725
		}
726
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
727
		if ( ! empty( $account ) ) {
728
			return $account;
729
		}
730
731
		return '';
732
	}
733
734
	/**
735
	 * Save the Publicized Facebook account when publishing a post
736
	 * Use only Personal accounts, not Facebook Pages
737
	 */
738
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
739
		$connection_meta = $this->get_connection_meta( $connection );
740
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
741
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
742
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
743
				$profile_link = $this->get_profile_link( 'facebook', $connection );
744
745
				if ( false !== $profile_link ) {
746
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
747
				}
748
			}
749
		}
750
	}
751
}
752