Completed
Push — branch-4.5 ( 44c43c...06de67 )
by
unknown
34:24 queued 24:42
created

Publicize   D

Complexity

Total Complexity 136

Size/Duplication

Total Lines 864
Duplicated Lines 1.97 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 0
Metric Value
dl 17
loc 864
rs 4.4444
c 0
b 0
f 0
wmc 136
lcom 2
cbo 6

42 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 38 1
A force_user_connection() 0 18 3
B admin_page_warning() 0 28 2
A disconnect() 0 11 2
A receive_updated_publicize_connections() 0 5 1
A register_update_publicize_connections_xmlrpc_method() 0 5 1
B get_connections() 0 17 7
A get_connection_id() 0 3 1
A get_connection_meta() 0 4 1
C admin_page_load() 0 72 9
C display_connection_error() 0 46 8
A display_disconnected() 0 5 1
A globalization() 0 18 4
A api_url() 0 22 3
A connect_url() 8 8 1
A refresh_url() 0 10 1
A disconnect_url() 9 9 1
B get_services() 0 28 5
A get_connection() 0 3 1
A flag_post_for_publicize() 0 21 4
B test_connection() 0 38 4
A save_publicized() 0 18 4
A set_post_flags() 0 20 4
F options_page_facebook() 0 115 17
C options_save_facebook() 0 42 7
C options_page_tumblr() 0 76 9
A get_basehostname() 0 3 1
A options_save_tumblr() 0 19 2
A options_page_twitter() 0 3 1
A options_page_linkedin() 0 3 1
A options_page_path() 0 3 1
A options_page_google_plus() 0 3 1
A options_save_twitter() 0 3 1
A options_save_linkedin() 0 3 1
A options_save_path() 0 3 1
A options_save_google_plus() 0 3 1
A options_save_other() 0 5 1
A publicize_checkbox_default() 0 7 2
B enhaced_twitter_cards_site_tag() 0 19 5
B save_publicized_twitter_account() 0 9 5
A get_publicized_twitter_account() 0 11 3
B save_publicized_facebook_account() 0 13 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Publicize often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Publicize, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
class Publicize extends Publicize_Base {
4
5
	function __construct() {
6
		parent::__construct();
7
8
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'register_update_publicize_connections_xmlrpc_method' ) );
9
10
		add_action( 'load-settings_page_sharing', array( $this, 'admin_page_load' ), 9 );
11
12
		add_action( 'wp_ajax_publicize_tumblr_options_page', array( $this, 'options_page_tumblr' ) );
13
		add_action( 'wp_ajax_publicize_facebook_options_page', array( $this, 'options_page_facebook' ) );
14
		add_action( 'wp_ajax_publicize_twitter_options_page', array( $this, 'options_page_twitter' ) );
15
		add_action( 'wp_ajax_publicize_linkedin_options_page', array( $this, 'options_page_linkedin' ) );
16
		add_action( 'wp_ajax_publicize_path_options_page', array( $this, 'options_page_path' ) );
17
		add_action( 'wp_ajax_publicize_google_plus_options_page', array( $this, 'options_page_google_plus' ) );
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
		add_action( 'wp_ajax_publicize_path_options_save', array( $this, 'options_save_path' ) );
24
		add_action( 'wp_ajax_publicize_google_plus_options_save', array( $this, 'options_save_google_plus' ) );
25
26
		add_action( 'load-settings_page_sharing', array( $this, 'force_user_connection' ) );
27
28
		add_filter( 'publicize_checkbox_default', array( $this, 'publicize_checkbox_default' ), 10, 4 );
29
30
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
31
32
		add_action( 'wp_insert_post', array( $this, 'save_publicized' ), 11, 3 );
33
34
		add_filter( 'jetpack_twitter_cards_site_tag', array( $this, 'enhaced_twitter_cards_site_tag' ) );
35
36
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_twitter_account' ), 10, 4 );
37
		add_action( 'publicize_save_meta', array( $this, 'save_publicized_facebook_account' ), 10, 4 );
38
39
		add_filter( 'jetpack_sharing_twitter_via', array( $this, 'get_publicized_twitter_account' ), 10, 2 );
40
41
		include_once( JETPACK__PLUGIN_DIR . 'modules/publicize/enhanced-open-graph.php' );
42
	}
43
44
	function force_user_connection() {
45
		global $current_user;
46
		$user_token        = Jetpack_Data::get_access_token( $current_user->ID );
47
		$is_user_connected = $user_token && ! is_wp_error( $user_token );
48
49
		// If the user is already connected via Jetpack, then we're good
50
		if ( $is_user_connected ) {
51
			return;
52
		}
53
54
		// If they're not connected, then remove the Publicize UI and tell them they need to connect first
55
		global $publicize_ui;
56
		remove_action( 'pre_admin_screen_sharing', array( $publicize_ui, 'admin_page' ) );
57
58
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
59
		// Jetpack::init()->admin_styles();
60
		add_action( 'pre_admin_screen_sharing', array( $this, 'admin_page_warning' ), 1 );
61
	}
62
63
	function admin_page_warning() {
64
		$jetpack   = Jetpack::init();
65
		$blog_name = get_bloginfo( 'blogname' );
66
		if ( empty( $blog_name ) ) {
67
			$blog_name = home_url( '/' );
68
		}
69
70
		?>
71
		<div id="message" class="updated jetpack-message jp-connect">
72
			<div class="jetpack-wrap-container">
73
				<div class="jetpack-text-container">
74
					<p><?php printf(
75
							esc_html( wptexturize( __( "To use Publicize, you'll need to link your %s account to your WordPress.com account using the link below.", 'jetpack' ) ) ),
76
							'<strong>' . esc_html( $blog_name ) . '</strong>'
77
						); ?></p>
78
					<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>
79
				</div>
80
				<div class="jetpack-install-container">
81
					<p class="submit"><a
82
							href="<?php echo $jetpack->build_connect_url( false, menu_page_url( 'sharing', false ) ); ?>"
83
							class="button-connector"
84
							id="wpcom-connect"><?php esc_html_e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
85
					</p>
86
				</div>
87
			</div>
88
		</div>
89
		<?php
90
	}
91
92
	/**
93
	 * Remove a Publicize connection
94
	 */
95
	function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
96
		Jetpack::load_xml_rpc_client();
97
		$xml = new Jetpack_IXR_Client();
98
		$xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
99
100
		if ( ! $xml->isError() ) {
101
			Jetpack_Options::update_option( 'publicize_connections', $xml->getResponse() );
102
		} else {
103
			return false;
104
		}
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_connections( $service_name, $_blog_id = false, $_user_id = false ) {
120
		$connections           = Jetpack_Options::get_option( 'publicize_connections' );
121
		$connections_to_return = array();
122
		if ( ! empty( $connections ) && is_array( $connections ) ) {
123
			if ( ! empty( $connections[ $service_name ] ) ) {
124
				foreach ( $connections[ $service_name ] as $id => $connection ) {
125
					if ( 0 == $connection['connection_data']['user_id'] || $this->user_id() == $connection['connection_data']['user_id'] ) {
126
						$connections_to_return[ $id ] = $connection;
127
					}
128
				}
129
			}
130
131
			return $connections_to_return;
132
		}
133
134
		return false;
135
	}
136
137
	function get_connection_id( $connection ) {
138
		return $connection['connection_data']['id'];
139
	}
140
141
	function get_connection_meta( $connection ) {
142
		$connection['user_id'] = $connection['connection_data']['user_id']; // Allows for shared connections
143
		return $connection;
144
	}
145
146
	function admin_page_load() {
147
		if ( isset( $_GET['action'] ) ) {
148
			if ( isset( $_GET['service'] ) ) {
149
				$service_name = $_GET['service'];
150
			}
151
152
			switch ( $_GET['action'] ) {
153
				case 'error':
154
					add_action( 'pre_admin_screen_sharing', array( $this, 'display_connection_error' ), 9 );
155
					break;
156
157
				case 'request':
158
					check_admin_referer( 'keyring-request', 'kr_nonce' );
159
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
0 ignored issues
show
Bug introduced by
The variable $service_name 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...
160
161
					$verification = Jetpack::create_nonce( 'publicize' );
162
163
					$stats_options = get_option( 'stats_options' );
164
					$wpcom_blog_id = Jetpack_Options::get_option( 'id' );
165
					$wpcom_blog_id = ! empty( $wpcom_blog_id ) ? $wpcom_blog_id : $stats_options['blog_id'];
166
167
					$user     = wp_get_current_user();
168
					$redirect = $this->api_url( $service_name, urlencode_deep( array(
169
						'action'       => 'request',
170
						'redirect_uri' => add_query_arg( array( 'action' => 'done' ), menu_page_url( 'sharing', false ) ),
171
						'for'          => 'publicize',
172
						// required flag that says this connection is intended for publicize
173
						'siteurl'      => site_url(),
174
						'state'        => $user->ID,
175
						'blog_id'      => $wpcom_blog_id,
176
						'secret_1'     => $verification['secret_1'],
177
						'secret_2'     => $verification['secret_2'],
178
						'eol'          => $verification['eol'],
179
					) ) );
180
					wp_redirect( $redirect );
181
					exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method admin_page_load() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
182
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
183
184
				case 'completed':
185
					Jetpack::load_xml_rpc_client();
186
					$xml = new Jetpack_IXR_Client();
187
					$xml->query( 'jetpack.fetchPublicizeConnections' );
188
189
					if ( ! $xml->isError() ) {
190
						$response = $xml->getResponse();
191
						Jetpack_Options::update_option( 'publicize_connections', $response );
192
					}
193
194
					break;
195
196
				case 'delete':
197
					$id = $_GET['id'];
198
199
					check_admin_referer( 'keyring-request', 'kr_nonce' );
200
					check_admin_referer( "keyring-request-$service_name", 'nonce' );
201
202
					$this->disconnect( $service_name, $id );
203
204
					add_action( 'admin_notices', array( $this, 'display_disconnected' ) );
205
					break;
206
			}
207
		}
208
209
		// Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
210
		// Errors encountered on WordPress.com's end are passed back as a code
211
		/*
212
		if ( isset( $_GET['action'] ) && 'error' == $_GET['action'] ) {
213
			// Load Jetpack's styles to handle the box
214
			Jetpack::init()->admin_styles();
215
		}
216
		*/
217
	}
218
219
	function display_connection_error() {
220
		$code = false;
221
		if ( isset( $_GET['service'] ) ) {
222
			$service_name = $_GET['service'];
223
			$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 ) );
224
		} else {
225
			if ( isset( $_GET['publicize_error'] ) ) {
226
				$code = strtolower( $_GET['publicize_error'] );
227
				switch ( $code ) {
228
					case '400':
229
						$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' );
230
						break;
231
					case 'secret_mismatch':
232
						$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' );
233
						break;
234
					case 'empty_blog_id':
235
						$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' );
236
						break;
237
					case 'empty_state':
238
						$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() );
239
						break;
240
					default:
241
						$error = __( 'Something which should never happen, happened. Sorry about that. If you try again, maybe it will work.', 'jetpack' );
242
						break;
243
				}
244
			} else {
245
				$error = __( 'There was a problem connecting with Publicize. Please try again in a moment.', 'jetpack' );
246
			}
247
		}
248
		// Using the same formatting/style as Jetpack::admin_notices() error
249
		?>
250
		<div id="message" class="jetpack-message jetpack-err">
251
			<div class="squeezer">
252
				<h2><?php echo wp_kses( $error, array( 'a'      => array( 'href' => true ),
253
				                                       'code'   => true,
254
				                                       'strong' => true,
255
				                                       'br'     => true,
256
				                                       'b'      => true
257
					) ); ?></h2>
258
				<?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...
259
					<p><?php printf( __( 'Error code: %s', 'jetpack' ), esc_html( stripslashes( $code ) ) ); ?></p>
260
				<?php endif; ?>
261
			</div>
262
		</div>
263
		<?php
264
	}
265
266
	function display_disconnected() {
267
		echo "<div class='updated'>\n";
268
		echo '<p>' . esc_html( __( 'That connection has been removed.', 'jetpack' ) ) . "</p>\n";
269
		echo "</div>\n\n";
270
	}
271
272
	function globalization() {
273
		if ( 'on' == $_REQUEST['global'] ) {
274
			$id = $_REQUEST['connection'];
275
276
			if ( ! current_user_can( $this->GLOBAL_CAP ) ) {
277
				return;
278
			}
279
280
			Jetpack::load_xml_rpc_client();
281
			$xml = new Jetpack_IXR_Client();
282
			$xml->query( 'jetpack.globalizePublicizeConnection', $id, 'globalize' );
283
284
			if ( ! $xml->isError() ) {
285
				$response = $xml->getResponse();
286
				Jetpack_Options::update_option( 'publicize_connections', $response );
287
			}
288
		}
289
	}
290
291
	/**
292
	 * Gets a URL to the public-api actions. Works like WP's admin_url
293
	 *
294
	 * @param string $service Shortname of a specific service.
295
	 *
296
	 * @return URL to specific public-api process
297
	 */
298
	// on WordPress.com this is/calls Keyring::admin_url
299
	function api_url( $service = false, $params = array() ) {
300
		/**
301
		 * Filters the API URL used to interact with WordPress.com.
302
		 *
303
		 * @module publicize
304
		 *
305
		 * @since 2.0.0
306
		 *
307
		 * @param string https://public-api.wordpress.com/connect/?jetpack=publicize Default Publicize API URL.
308
		 */
309
		$url = apply_filters( 'publicize_api_url', 'https://public-api.wordpress.com/connect/?jetpack=publicize' );
310
311
		if ( $service ) {
312
			$url = add_query_arg( array( 'service' => $service ), $url );
313
		}
314
315
		if ( count( $params ) ) {
316
			$url = add_query_arg( $params, $url );
317
		}
318
319
		return $url;
320
	}
321
322 View Code Duplication
	function connect_url( $service_name ) {
323
		return add_query_arg( array(
324
			'action'   => 'request',
325
			'service'  => $service_name,
326
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
327
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
328
		), menu_page_url( 'sharing', false ) );
329
	}
330
331
	function refresh_url( $service_name ) {
332
		return add_query_arg( array(
333
			'action'   => 'request',
334
			'service'  => $service_name,
335
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
336
			'refresh'  => 1,
337
			'for'      => 'publicize',
338
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
339
		), admin_url( 'options-general.php?page=sharing' ) );
340
	}
341
342 View Code Duplication
	function disconnect_url( $service_name, $id ) {
343
		return add_query_arg( array(
344
			'action'   => 'delete',
345
			'service'  => $service_name,
346
			'id'       => $id,
347
			'kr_nonce' => wp_create_nonce( 'keyring-request' ),
348
			'nonce'    => wp_create_nonce( "keyring-request-$service_name" ),
349
		), menu_page_url( 'sharing', false ) );
350
	}
351
352
	function get_services( $filter ) {
353
		if ( ! in_array( $filter, array( 'all', 'connected' ) ) ) {
354
			$filter = 'all';
355
		}
356
357
		$services = array(
358
			'facebook'    => array(),
359
			'twitter'     => array(),
360
			'linkedin'    => array(),
361
			'tumblr'      => array(),
362
			'path'        => array(),
363
			'google_plus' => array(),
364
		);
365
366
		if ( 'all' == $filter ) {
367
			return $services;
368
		} else {
369
			$connected_services = array();
370
			foreach ( $services as $service => $empty ) {
371
				$connections = $this->get_connections( $service );
372
				if ( $connections ) {
373
					$connected_services[ $service ] = $connections;
374
				}
375
			}
376
377
			return $connected_services;
378
		}
379
	}
380
381
	function get_connection( $service, $id, $_blog_id = false, $_user_id = false ) {
382
		// Stub
383
	}
384
385
	function flag_post_for_publicize( $new_status, $old_status, $post ) {
386
		if ( 'publish' == $new_status && 'publish' != $old_status ) {
387
			/**
388
			 * Determines whether a post being published gets publicized.
389
			 *
390
			 * Side-note: Possibly our most alliterative filter name.
391
			 *
392
			 * @module publicize
393
			 *
394
			 * @since 4.1.0
395
			 *
396
			 * @param bool $should_publicize Should the post be publicized? Default to true.
397
			 * @param WP_POST $post Current Post object.
398
			 */
399
			$should_publicize = apply_filters( 'publicize_should_publicize_published_post', true, $post );
400
401
			if ( $should_publicize ) {
402
				update_post_meta( $post->ID, $this->PENDING, true );
403
			}
404
		}
405
	}
406
407
	function test_connection( $service_name, $connection ) {
408
		$connection_test_passed  = true;
409
		$connection_test_message = '';
410
		$user_can_refresh        = false;
0 ignored issues
show
Unused Code introduced by
$user_can_refresh 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...
411
412
		$id = $this->get_connection_id( $connection );
413
414
		Jetpack::load_xml_rpc_client();
415
		$xml = new Jetpack_IXR_Client();
416
		$xml->query( 'jetpack.testPublicizeConnection', $id );
417
418
		if ( $xml->isError() ) {
419
			$xml_response            = $xml->getResponse();
420
			$connection_test_message = $xml_response['faultString'];
421
			$connection_test_passed  = false;
422
		}
423
424
		// Bail if all is well
425
		if ( $connection_test_passed ) {
426
			return true;
427
		}
428
429
		// Set up refresh if the user can
430
		$user_can_refresh = current_user_can( $this->GLOBAL_CAP );
431
		if ( $user_can_refresh ) {
432
			$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...
433
			$refresh_text = sprintf( _x( 'Refresh connection with %s', 'Refresh connection with {social media service}', 'jetpack' ), $this->get_service_label( $service_name ) );
434
			$refresh_url  = $this->refresh_url( $service_name );
435
		}
436
437
		$error_data = array(
438
			'user_can_refresh' => $user_can_refresh,
439
			'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...
440
			'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...
441
		);
442
443
		return new WP_Error( 'pub_conn_test_failed', $connection_test_message, $error_data );
444
	}
445
446
	/**
447
	 * Save a flag locally to indicate that this post has already been Publicized via the selected
448
	 * connections.
449
	 */
450
	function save_publicized( $post_ID, $post, $update ) {
0 ignored issues
show
Unused Code introduced by
The parameter $update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
451
		// Only do this when a post transitions to being published
452
		if ( get_post_meta( $post->ID, $this->PENDING ) && $this->post_type_is_publicizeable( $post->post_type ) ) {
453
			$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
454
			if ( ! empty( $connected_services ) ) {
455
				/**
456
				 * Fires when a post is saved that has is marked as pending publicizing
457
				 *
458
				 * @since 4.1.0
459
				 *
460
				 * @param int The post ID
461
				 */
462
				do_action( 'jetpack_publicize_post', $post->ID );
463
			}
464
			delete_post_meta( $post->ID, $this->PENDING );
465
			update_post_meta( $post->ID, $this->POST_DONE . 'all', true );
466
		}
467
	}
468
469
	function set_post_flags( $flags, $post ) {
470
		$flags['publicize_post'] = false;
471
		if ( ! $this->post_type_is_publicizeable( $post->post_type ) ) {
472
			return $flags;
473
		}
474
		/** This filter is already documented in modules/publicize/publicize-jetpack.php */
475
		if ( ! apply_filters( 'publicize_should_publicize_published_post', true, $post ) ) {
476
			return $flags;
477
		}
478
479
		$connected_services = $this->get_services( 'connected' );
480
481
		if ( empty( $connected_services ) ) {
482
			return $flags;
483
		}
484
485
		$flags['publicize_post'] = true;
486
487
		return $flags;
488
	}
489
490
	/**
491
	 * Options Code
492
	 */
493
494
	function options_page_facebook() {
495
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
496
		$connection         = $connected_services['facebook'][ $_REQUEST['connection'] ];
497
		$options_to_show    = ( ! empty( $connection['connection_data']['meta']['options_responses'] ) ? $connection['connection_data']['meta']['options_responses'] : false );
498
499
		// Nonce check
500
		check_admin_referer( 'options_page_facebook_' . $_REQUEST['connection'] );
501
502
		$me    = ( ! empty( $options_to_show[0] ) ? $options_to_show[0] : false );
503
		$pages = ( ! empty( $options_to_show[1]['data'] ) ? $options_to_show[1]['data'] : false );
504
505
		$profile_checked = true;
506
		$page_selected   = false;
507
508
		if ( ! empty( $connection['connection_data']['meta']['facebook_page'] ) ) {
509
			$found = false;
510
			if ( is_array( $pages->data ) ) {
511
				foreach ( $pages->data as $page ) {
512
					if ( $page->id == $connection['connection_data']['meta']['facebook_page'] ) {
513
						$found = true;
514
						break;
515
					}
516
				}
517
			}
518
519
			if ( $found ) {
520
				$profile_checked = false;
521
				$page_selected   = $connection['connection_data']['meta']['facebook_page'];
522
			}
523
		}
524
525
		?>
526
527
		<div id="thickbox-content">
528
529
			<?php
530
			ob_start();
531
			Publicize_UI::connected_notice( 'Facebook' );
532
			$update_notice = ob_get_clean();
533
534
			if ( ! empty( $update_notice ) ) {
535
				echo $update_notice;
536
			}
537
			?>
538
539
			<?php if ( ! empty( $me['name'] ) ) : ?>
540
				<p><?php printf(
541
						esc_html__( 'Publicize to my %s:', 'jetpack' ),
542
						'<strong>' . esc_html__( 'Facebook Wall', 'jetpack' ) . '</strong>'
543
					); ?></p>
544
				<table id="option-profile">
545
					<tbody>
546
					<tr>
547
						<td class="radio"><input type="radio" name="option" data-type="profile"
548
						                         id="<?php echo esc_attr( $me['id'] ) ?>"
549
						                         value="" <?php checked( $profile_checked, true ); ?> /></td>
550
						<td class="thumbnail"><label for="<?php echo esc_attr( $me['id'] ) ?>"><img
551
									src="<?php echo esc_url( $me['picture']['data']['url'] ) ?>" width="50"
552
									height="50"/></label></td>
553
						<td class="details"><label
554
								for="<?php echo esc_attr( $me['id'] ) ?>"><?php echo esc_html( $me['name'] ) ?></label>
555
						</td>
556
					</tr>
557
					</tbody>
558
				</table>
559
			<?php endif; ?>
560
561
			<?php if ( $pages ) : ?>
562
563
				<p><?php printf(
564
						esc_html__( 'Publicize to my %s:', 'jetpack' ),
565
						'<strong>' . esc_html__( 'Facebook Page', 'jetpack' ) . '</strong>'
566
					); ?></p>
567
				<table id="option-fb-fanpage">
568
					<tbody>
569
570
					<?php foreach ( $pages as $i => $page ) : ?>
571
						<?php if ( ! ( $i % 2 ) ) : ?>
572
							<tr>
573
						<?php endif; ?>
574
						<td class="radio"><input type="radio" name="option" data-type="page"
575
						                         id="<?php echo esc_attr( $page['id'] ) ?>"
576
						                         value="<?php echo esc_attr( $page['id'] ) ?>" <?php checked( $page_selected && $page_selected == $page['id'], true ); ?> />
577
						</td>
578
						<td class="thumbnail"><label for="<?php echo esc_attr( $page['id'] ) ?>"><img
579
									src="<?php echo esc_url( str_replace( '_s', '_q', $page['picture']['data']['url'] ) ) ?>"
580
									width="50" height="50"/></label></td>
581
						<td class="details">
582
							<label for="<?php echo esc_attr( $page['id'] ) ?>">
583
								<span class="name"><?php echo esc_html( $page['name'] ) ?></span><br/>
584
								<span class="category"><?php echo esc_html( $page['category'] ) ?></span>
585
							</label>
586
						</td>
587
						<?php if ( ( $i % 2 ) || ( $i == count( $pages ) - 1 ) ): ?>
588
							</tr>
589
						<?php endif; ?>
590
					<?php endforeach; ?>
591
592
					</tbody>
593
				</table>
594
595
			<?php endif; ?>
596
597
			<?php Publicize_UI::global_checkbox( 'facebook', $_REQUEST['connection'] ); ?>
598
599
			<p style="text-align: center;">
600
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
601
				       class="button fb-options save-options" name="save"
602
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
603
				       rel="<?php echo wp_create_nonce( 'save_fb_token_' . $_REQUEST['connection'] ) ?>"/>
604
			</p><br/>
605
		</div>
606
607
		<?php
608
	}
609
610
	function options_save_facebook() {
611
		// Nonce check
612
		check_admin_referer( 'save_fb_token_' . $_REQUEST['connection'] );
613
614
		$id = $_POST['connection'];
615
616
		// Check for a numeric page ID
617
		$page_id = $_POST['selected_id'];
618
		if ( ! ctype_digit( $page_id ) ) {
619
			die( 'Security check' );
0 ignored issues
show
Coding Style Compatibility introduced by
The method options_save_facebook() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
620
		}
621
622
		if ( isset( $_POST['selected_id'] ) && 'profile' == $_POST['type'] ) {
623
			// Publish to User Wall/Profile
624
			$options = array(
625
				'facebook_page'    => null,
626
				'facebook_profile' => true
627
			);
628
629
		} else {
630
			if ( 'page' != $_POST['type'] || ! isset( $_POST['selected_id'] ) ) {
631
				return;
632
			}
633
634
			// Publish to Page
635
			$options = array(
636
				'facebook_page'    => $page_id,
637
				'facebook_profile' => null
638
			);
639
		}
640
641
		Jetpack::load_xml_rpc_client();
642
		$xml = new Jetpack_IXR_Client();
643
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
644
645
		if ( ! $xml->isError() ) {
646
			$response = $xml->getResponse();
647
			Jetpack_Options::update_option( 'publicize_connections', $response );
648
		}
649
650
		$this->globalization();
651
	}
652
653
	function options_page_tumblr() {
654
		// Nonce check
655
		check_admin_referer( 'options_page_tumblr_' . $_REQUEST['connection'] );
656
657
		$connected_services = Jetpack_Options::get_option( 'publicize_connections' );
658
		$connection         = $connected_services['tumblr'][ $_POST['connection'] ];
659
		$options_to_show    = $connection['connection_data']['meta']['options_responses'];
660
		$request            = $options_to_show[0];
661
662
		$blogs = $request['response']['user']['blogs'];
663
664
		$blog_selected = false;
665
666
		if ( ! empty( $connection['connection_data']['meta']['tumblr_base_hostname'] ) ) {
667
			foreach ( $blogs as $blog ) {
668
				if ( $connection['connection_data']['meta']['tumblr_base_hostname'] == $this->get_basehostname( $blog['url'] ) ) {
669
					$blog_selected = $connection['connection_data']['meta']['tumblr_base_hostname'];
670
					break;
671
				}
672
			}
673
674
		}
675
676
		// Use their Primary blog if they haven't selected one yet
677
		if ( ! $blog_selected ) {
678
			foreach ( $blogs as $blog ) {
679
				if ( $blog['primary'] ) {
680
					$blog_selected = $this->get_basehostname( $blog['url'] );
681
				}
682
			}
683
		} ?>
684
685
		<div id="thickbox-content">
686
687
			<?php
688
			ob_start();
689
			Publicize_UI::connected_notice( 'Tumblr' );
690
			$update_notice = ob_get_clean();
691
692
			if ( ! empty( $update_notice ) ) {
693
				echo $update_notice;
694
			}
695
			?>
696
697
			<p><?php printf(
698
					esc_html__( 'Publicize to my %s:', 'jetpack' ),
699
					'<strong>' . esc_html__( 'Tumblr blog', 'jetpack' ) . '</strong>'
700
				); ?></p>
701
702
			<ul id="option-tumblr-blog">
703
704
				<?php
705
				foreach ( $blogs as $blog ) {
706
					$url = $this->get_basehostname( $blog['url'] ); ?>
707
					<li>
708
						<input type="radio" name="option" data-type="blog" id="<?php echo esc_attr( $url ) ?>"
709
						       value="<?php echo esc_attr( $url ) ?>" <?php checked( $blog_selected == $url, true ); ?> />
710
						<label for="<?php echo esc_attr( $url ) ?>"><span
711
								class="name"><?php echo esc_html( $blog['title'] ) ?></span></label>
712
					</li>
713
				<?php } ?>
714
715
			</ul>
716
717
			<?php Publicize_UI::global_checkbox( 'tumblr', $_REQUEST['connection'] ); ?>
718
719
			<p style="text-align: center;">
720
				<input type="submit" value="<?php esc_attr_e( 'OK', 'jetpack' ) ?>"
721
				       class="button tumblr-options save-options" name="save"
722
				       data-connection="<?php echo esc_attr( $_REQUEST['connection'] ); ?>"
723
				       rel="<?php echo wp_create_nonce( 'save_tumblr_blog_' . $_REQUEST['connection'] ) ?>"/>
724
			</p> <br/>
725
		</div>
726
727
		<?php
728
	}
729
730
	function get_basehostname( $url ) {
731
		return parse_url( $url, PHP_URL_HOST );
732
	}
733
734
	function options_save_tumblr() {
735
		// Nonce check
736
		check_admin_referer( 'save_tumblr_blog_' . $_REQUEST['connection'] );
737
738
		$id = $_POST['connection'];
739
740
		$options = array( 'tumblr_base_hostname' => $_POST['selected_id'] );
741
742
		Jetpack::load_xml_rpc_client();
743
		$xml = new Jetpack_IXR_Client();
744
		$xml->query( 'jetpack.setPublicizeOptions', $id, $options );
745
746
		if ( ! $xml->isError() ) {
747
			$response = $xml->getResponse();
748
			Jetpack_Options::update_option( 'publicize_connections', $response );
749
		}
750
751
		$this->globalization();
752
	}
753
754
	function options_page_twitter() {
755
		Publicize_UI::options_page_other( 'twitter' );
756
	}
757
758
	function options_page_linkedin() {
759
		Publicize_UI::options_page_other( 'linkedin' );
760
	}
761
762
	function options_page_path() {
763
		Publicize_UI::options_page_other( 'path' );
764
	}
765
766
	function options_page_google_plus() {
767
		Publicize_UI::options_page_other( 'google_plus' );
768
	}
769
770
	function options_save_twitter() {
771
		$this->options_save_other( 'twitter' );
772
	}
773
774
	function options_save_linkedin() {
775
		$this->options_save_other( 'linkedin' );
776
	}
777
778
	function options_save_path() {
779
		$this->options_save_other( 'path' );
780
	}
781
782
	function options_save_google_plus() {
783
		$this->options_save_other( 'google_plus' );
784
	}
785
786
	function options_save_other( $service_name ) {
787
		// Nonce check
788
		check_admin_referer( 'save_' . $service_name . '_token_' . $_REQUEST['connection'] );
789
		$this->globalization();
790
	}
791
792
	/**
793
	 * Already-published posts should not be Publicized by default. This filter sets checked to
794
	 * false if a post has already been published.
795
	 */
796
	function publicize_checkbox_default( $checked, $post_id, $name, $connection ) {
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $connection is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
797
		if ( 'publish' == get_post_status( $post_id ) ) {
798
			return false;
799
		}
800
801
		return $checked;
802
	}
803
804
	/**
805
	 * If there's only one shared connection to Twitter set it as twitter:site tag.
806
	 */
807
	function enhaced_twitter_cards_site_tag( $tag ) {
808
		$custom_site_tag = get_option( 'jetpack-twitter-cards-site-tag' );
809
		if ( ! empty( $custom_site_tag ) ) {
810
			return $tag;
811
		}
812
		if ( ! $this->is_enabled( 'twitter' ) ) {
813
			return $tag;
814
		}
815
		$connections = $this->get_connections( 'twitter' );
816
		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...
817
			$connection_meta = $this->get_connection_meta( $connection );
818
			if ( 0 == $connection_meta['connection_data']['user_id'] ) {
819
				// If the connection is shared
820
				return $this->get_display_name( 'twitter', $connection );
821
			}
822
		}
823
824
		return $tag;
825
	}
826
827
	function save_publicized_twitter_account( $submit_post, $post_id, $service_name, $connection ) {
828
		if ( 'twitter' == $service_name && $submit_post ) {
829
			$connection_meta        = $this->get_connection_meta( $connection );
830
			$publicize_twitter_user = get_post_meta( $post_id, '_publicize_twitter_user' );
831
			if ( empty( $publicize_twitter_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
832
				update_post_meta( $post_id, '_publicize_twitter_user', $this->get_display_name( 'twitter', $connection ) );
833
			}
834
		}
835
	}
836
837
	function get_publicized_twitter_account( $account, $post_id ) {
838
		if ( ! empty( $account ) ) {
839
			return $account;
840
		}
841
		$account = get_post_meta( $post_id, '_publicize_twitter_user', true );
842
		if ( ! empty( $account ) ) {
843
			return $account;
844
		}
845
846
		return '';
847
	}
848
849
	/**
850
	 * Save the Publicized Facebook account when publishing a post
851
	 * Use only Personal accounts, not Facebook Pages
852
	 */
853
	function save_publicized_facebook_account( $submit_post, $post_id, $service_name, $connection ) {
854
		$connection_meta = $this->get_connection_meta( $connection );
855
		if ( 'facebook' == $service_name && isset( $connection_meta['connection_data']['meta']['facebook_profile'] ) && $submit_post ) {
856
			$publicize_facebook_user = get_post_meta( $post_id, '_publicize_facebook_user' );
857
			if ( empty( $publicize_facebook_user ) || 0 != $connection_meta['connection_data']['user_id'] ) {
858
				$profile_link = $this->get_profile_link( 'facebook', $connection );
859
860
				if ( false !== $profile_link ) {
861
					update_post_meta( $post_id, '_publicize_facebook_user', $profile_link );
862
				}
863
			}
864
		}
865
	}
866
}
867