install_plugin_information()   F
last analyzed

Complexity

Conditions 68
Paths > 20000

Size

Total Lines 396
Code Lines 273

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 396
rs 2
nc 1592524801
cc 68
eloc 273
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 19 and the first side effect is on line 10.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
	/**
3
	 * @package     Freemius
4
	 * @copyright   Copyright (c) 2015, Freemius, Inc.
5
	 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
6
	 * @since       1.0.6
7
	 */
8
9
	if ( ! defined( 'ABSPATH' ) ) {
10
		exit;
11
	}
12
13
	/**
14
	 * Class FS_Plugin_Info_Dialog
15
	 *
16
	 * @author Vova Feldman (@svovaf)
17
	 * @since  1.1.7
18
	 */
19
	class FS_Plugin_Info_Dialog {
20
		/**
21
		 * @since 1.1.7
22
		 *
23
		 * @var FS_Logger
24
		 */
25
		private $_logger;
26
27
		/**
28
		 * @since 1.1.7
29
		 *
30
		 * @var Freemius
31
		 */
32
		private $_fs;
33
34
		function __construct( Freemius $fs ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
35
			$this->_fs = $fs;
36
37
			$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
38
39
			// Remove default plugin information action.
40
			remove_all_actions( 'install_plugins_pre_plugin-information' );
41
42
			// Override action with custom plugins function for add-ons.
43
			add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
44
45
			// Override request for plugin information for Add-ons.
46
			add_filter(
47
				'fs_plugins_api',
48
				array( &$this, '_get_addon_info_filter' ),
49
				WP_FS__DEFAULT_PRIORITY, 3 );
50
		}
51
52
		/**
53
		 * Generate add-on plugin information.
54
		 *
55
		 * @author Vova Feldman (@svovaf)
56
		 * @since  1.0.6
57
		 *
58
		 * @param array       $data
59
		 * @param string      $action
60
		 * @param object|null $args
61
		 *
62
		 * @return array|null
63
		 */
64
		function _get_addon_info_filter( $data, $action = '', $args = null ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
65
			$this->_logger->entrance();
66
67
			$parent_plugin_id = fs_request_get( 'parent_plugin_id', false );
68
69
			if ( $this->_fs->get_id() != $parent_plugin_id ||
70
			     ( 'plugin_information' !== $action ) ||
71
			     ! isset( $args->slug )
72
			) {
73
				return $data;
74
			}
75
76
			// Find add-on by slug.
77
			$addons         = $this->_fs->get_addons();
78
			$selected_addon = false;
79
			foreach ( $addons as $addon ) {
0 ignored issues
show
Bug introduced by
The expression $addons of type array<integer,object<FS_Plugin>>|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...
80
				if ( $addon->slug == $args->slug ) {
81
					$selected_addon = $addon;
82
					break;
83
				}
84
			}
85
86
			if ( false === $selected_addon ) {
87
				return $data;
88
			}
89
90
			if ( ! isset( $selected_addon->info ) ) {
91
				// Setup some default info.
92
				$selected_addon->info                  = new stdClass();
93
				$selected_addon->info->selling_point_0 = 'Selling Point 1';
94
				$selected_addon->info->selling_point_1 = 'Selling Point 2';
95
				$selected_addon->info->selling_point_2 = 'Selling Point 3';
96
				$selected_addon->info->description     = '<p>Tell your users all about your add-on</p>';
97
			}
98
99
			fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
100
101
			$data = $args;
102
103
			$is_free = true;
104
105
			// Load add-on pricing.
106
			$has_pricing  = false;
107
			$has_features = false;
108
			$plans        = false;
109
			$plans_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans.json" );
110
			if ( ! isset( $plans_result->error ) ) {
111
				$plans = $plans_result->plans;
112
				if ( is_array( $plans ) ) {
113
					for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
114
						$plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
115
						$plan        = $plans[ $i ];
116
117
						$pricing_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/pricing.json" );
118
						if ( ! isset( $pricing_result->error ) ) {
119
							// Update plan's pricing.
120
							$plan->pricing = $pricing_result->pricing;
0 ignored issues
show
Bug introduced by
The property pricing does not seem to exist in FS_Plugin_Plan.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
121
122
							if ( is_array( $plan->pricing ) && ! empty( $plan->pricing ) ) {
123
								$is_free = false;
124
125
								foreach ( $plan->pricing as &$pricing ) {
126
									$pricing = new FS_Pricing( $pricing );
127
								}
128
							}
129
130
							$has_pricing = true;
131
						}
132
133
						$features_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/features.json" );
134
						if ( ! isset( $features_result->error ) &&
135
						     is_array( $features_result->features ) &&
136
						     0 < count( $features_result->features )
137
						) {
138
							// Update plan's pricing.
139
							$plan->features = $features_result->features;
0 ignored issues
show
Bug introduced by
The property features does not seem to exist. Did you mean is_block_features?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
140
141
							$has_features = true;
142
						}
143
					}
144
				}
145
			}
146
147
			// Fetch latest version from Freemius.
148
			$latest = $this->_fs->_fetch_latest_version( $selected_addon->id );
149
150
			if ( ! $is_free ) {
151
				// If paid add-on, then it's not on wordpress.org
152
				$is_wordpress_org = false;
153
			} else {
154
				// If no versions found, then assume it's a .org plugin.
155
				$is_wordpress_org = ( false === $latest );
156
			}
157
158
			if ( $is_wordpress_org ) {
159
				$repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
160
					'plugin_information', (object) array(
161
						'slug'   => $selected_addon->slug,
162
						'is_ssl' => is_ssl(),
163
						'fields' => array(
164
							'banners'         => true,
165
							'reviews'         => true,
166
							'downloaded'      => false,
167
							'active_installs' => true
168
						)
169
					) );
170
171
				if ( ! empty( $repo_data ) ) {
172
					$data                 = $repo_data;
173
					$data->wp_org_missing = false;
174
				} else {
175
					// Couldn't find plugin on .org.
176
					$is_wordpress_org = false;
177
178
					// Plugin is missing, not on Freemius nor WP.org.
179
					$data->wp_org_missing = true;
180
				}
181
			}
182
183
			if ( ! $is_wordpress_org ) {
184
				$data->checkout_link = $this->_fs->checkout_url();
185
				$data->fs_missing    = ( false === $latest );
186
187
				if ( $is_free ) {
188
					$data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
189
				}
190
			}
191
192
			if ( ! $is_wordpress_org ) {
193
// Fetch as much as possible info from local files.
194
				$plugin_local_data = $this->_fs->get_plugin_data();
195
				$data->name        = $selected_addon->title;
196
				$data->author      = $plugin_local_data['Author'];
197
				$view_vars         = array( 'plugin' => $selected_addon );
198
				$data->sections    = array(
199
					'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
200
				);
201
202
				if ( ! empty( $selected_addon->info->banner_url ) ) {
203
					$data->banners = array(
204
						'low' => $selected_addon->info->banner_url,
205
					);
206
				}
207
208
				if ( ! empty( $selected_addon->info->screenshots ) ) {
209
					$view_vars                     = array(
210
						'screenshots' => $selected_addon->info->screenshots,
211
						'plugin'      => $selected_addon,
212
					);
213
					$data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
214
				}
215
216
				if ( is_object( $latest ) ) {
217
					$data->version      = $latest->version;
218
					$data->last_updated = ! is_null( $latest->updated ) ? $latest->updated : $latest->created;
219
					$data->requires     = $latest->requires_platform_version;
220
					$data->tested       = $latest->tested_up_to_version;
221
				} else {
222
					// Add dummy version.
223
					$data->version = '1.0.0';
224
225
					// Add message to developer to deploy the plugin through Freemius.
226
				}
227
			}
228
229
			if ( $has_pricing ) {
230
				// Add plans to data.
231
				$data->plans = $plans;
232
233
				if ( $has_features ) {
234
					$view_vars                  = array(
235
						'plans'  => $plans,
236
						'plugin' => $selected_addon,
237
					);
238
					$data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
239
				}
240
			}
241
242
			$data->is_paid  = ! $is_free;
243
			$data->external = ! $is_wordpress_org;
244
245
			return $data;
246
		}
247
248
		/**
249
		 * @author Vova Feldman (@svovaf)
250
		 * @since  1.1.7
251
		 *
252
		 * @param FS_Plugin_Plan $plan
253
		 *
254
		 * @return string
255
		 */
256
		private function get_billing_cycle( FS_Plugin_Plan $plan ) {
257
			$billing_cycle = null;
258
259
			if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
260
				$pricing = $plan->pricing[0];
0 ignored issues
show
Bug introduced by
The property pricing does not seem to exist in FS_Plugin_Plan.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
261
				if ( isset( $pricing->annual_price ) ) {
262
					$billing_cycle = 'annual';
263
				} else if ( isset( $pricing->monthly_price ) ) {
264
					$billing_cycle = 'monthly';
265
				} else if ( isset( $pricing->lifetime_price ) ) {
266
					$billing_cycle = 'lifetime';
267
				}
268
			} else {
269
				foreach ( $plan->pricing as $pricing ) {
270
					if ( isset( $pricing->annual_price ) ) {
271
						$billing_cycle = 'annual';
272
					} else if ( isset( $pricing->monthly_price ) ) {
273
						$billing_cycle = 'monthly';
274
					} else if ( isset( $pricing->lifetime_price ) ) {
275
						$billing_cycle = 'lifetime';
276
					}
277
278
					if ( ! is_null( $billing_cycle ) ) {
279
						break;
280
					}
281
				}
282
			}
283
284
			return $billing_cycle;
285
		}
286
287
		/**
288
		 * @author Vova Feldman (@svovaf)
289
		 * @since  1.1.7
290
		 *
291
		 * @param \FS_Plugin_Plan $plan
292
		 * @param \FS_Pricing     $pricing
293
		 *
294
		 * @return float|null|string
295
		 */
296
		private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
297
			$price_tag = '';
298
			if ( isset( $pricing->annual_price ) ) {
299
				$price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
300
			} else if ( isset( $pricing->monthly_price ) ) {
301
				$price_tag = $pricing->monthly_price . ' / mo';
302
			} else if ( isset( $pricing->lifetime_price ) ) {
303
				$price_tag = $pricing->lifetime_price;
304
			}
305
306
			return '$' . $price_tag;
307
		}
308
309
		/**
310
		 * @author Vova Feldman (@svovaf)
311
		 * @since  1.1.7
312
		 *
313
		 * @param object              $api
314
		 * @param FS_Plugin_Plan|null $plan
315
		 *
316
		 * @return string
317
		 */
318
		private function get_plugin_cta( $api, $plan = null ) {
319
			if ( ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
320
321
				if ( ! empty( $api->checkout_link ) && isset( $api->plans ) && 0 < is_array( $api->plans ) ) {
322
					if ( is_null( $plan ) ) {
323
						$plan = $api->plans[0];
324
					}
325
326
					return ' <a class="button button-primary right" href="' . $this->_fs->addon_checkout_url(
327
						$plan->plugin_id,
328
						$plan->pricing[0]->id,
329
						$this->get_billing_cycle( $plan ),
330
						$plan->has_trial()
331
					) . '" target="_parent">' .
332
					       ( ! $plan->has_trial() ?
333
						       __fs( 'purchase', $api->slug ) :
334
						       sprintf( __fs( 'start-free-x', $api->slug ), $this->get_trial_period( $plan ) )
335
					       ) .
336
					       '</a>';
337
338
					// @todo Add Cart concept.
339
//			echo ' <a class="button right" href="' . $status['url'] . '" target="_parent">' . __( 'Add to Cart' ) . '</a>';
340
341
				} else if ( ! empty( $api->download_link ) ) {
342
					$status = install_plugin_install_status( $api );
343
344
345
					// Hosted on WordPress.org.
346
					switch ( $status['status'] ) {
347
						case 'install':
348
							if ( $api->external &&
349
							     $this->_fs->is_org_repo_compliant() ||
350
							     ! $this->_fs->is_premium()
351
							) {
352
								/**
353
								 * Add-on hosted on Freemius, not yet installed, and core
354
								 * plugin is wordpress.org compliant. Therefore, require a download
355
								 * since installing external plugins is not allowed by the wp.org guidelines.
356
								 */
357
								return ' <a class="button button-primary right" href="' . esc_url( $api->download_link ) . '" target="_blank">' . __fs( 'download-latest', $api->slug ) . '</a>';
358
							} else {
359
								if ( $status['url'] ) {
360
									return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>';
361
								}
362
							}
363
							break;
364
						case 'update_available':
365
							if ( $status['url'] ) {
366
								return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) . '</a>';
367
							}
368
							break;
369
						case 'newer_installed':
370
							return '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed' ), $status['version'] ) . '</a>';
371
							break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
372
						case 'latest_installed':
373
							return '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>';
374
							break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
375
					}
376
377
				}
378
			}
379
		}
380
381
		/**
382
		 * @author Vova Feldman (@svovaf)
383
		 * @since  1.1.7
384
		 *
385
		 * @param FS_Plugin_Plan $plan
386
		 *
387
		 * @return string
388
		 */
389
		private function get_trial_period( $plan ) {
390
			$trial_period = (int) $plan->trial_period;
391
392
			switch ( $trial_period ) {
393
				case 30:
394
					return 'month';
395
				case 60:
396
					return '2 months';
397
				default:
398
					return "{$plan->trial_period} days";
399
			}
400
		}
401
402
		/**
403
		 * Display plugin information in dialog box form.
404
		 *
405
		 * Based on core install_plugin_information() function.
406
		 *
407
		 * @author Vova Feldman (@svovaf)
408
		 * @since  1.0.6
409
		 */
410
		function install_plugin_information() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
411
			global $tab;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
412
413
			if ( empty( $_REQUEST['plugin'] ) ) {
414
				return;
415
			}
416
417
			$args = array(
418
				'slug'   => wp_unslash( $_REQUEST['plugin'] ),
419
				'is_ssl' => is_ssl(),
420
				'fields' => array(
421
					'banners'         => true,
422
					'reviews'         => true,
423
					'downloaded'      => false,
424
					'active_installs' => true
425
				)
426
			);
427
428
			if ( is_array( $args ) ) {
429
				$args = (object) $args;
430
			}
431
432
			if ( ! isset( $args->per_page ) ) {
433
				$args->per_page = 24;
434
			}
435
436
			if ( ! isset( $args->locale ) ) {
437
				$args->locale = get_locale();
438
			}
439
440
			$api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
441
442
			if ( is_wp_error( $api ) ) {
443
				wp_die( $api );
444
			}
445
446
			$plugins_allowedtags = array(
447
				'a'       => array(
448
					'href'   => array(),
449
					'title'  => array(),
450
					'target' => array(),
451
					// Add image style for screenshots.
452
					'class'  => array()
453
				),
454
				'style'   => array(),
455
				'abbr'    => array( 'title' => array() ),
456
				'acronym' => array( 'title' => array() ),
457
				'code'    => array(),
458
				'pre'     => array(),
459
				'em'      => array(),
460
				'strong'  => array(),
461
				'div'     => array( 'class' => array() ),
462
				'span'    => array( 'class' => array() ),
463
				'p'       => array(),
464
				'ul'      => array(),
465
				'ol'      => array(),
466
				'li'      => array( 'class' => array() ),
467
				'i'       => array( 'class' => array() ),
468
				'h1'      => array(),
469
				'h2'      => array(),
470
				'h3'      => array(),
471
				'h4'      => array(),
472
				'h5'      => array(),
473
				'h6'      => array(),
474
				'img'     => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
475
//			'table' => array(),
0 ignored issues
show
Unused Code Comprehensibility introduced by
51% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
476
//			'td' => array(),
477
//			'tr' => array(),
478
//			'th' => array(),
479
//			'thead' => array(),
480
//			'tbody' => array(),
481
			);
482
483
			$plugins_section_titles = array(
484
				'description'  => _x( 'Description', 'Plugin installer section title' ),
485
				'installation' => _x( 'Installation', 'Plugin installer section title' ),
486
				'faq'          => _x( 'FAQ', 'Plugin installer section title' ),
487
				'screenshots'  => _x( 'Screenshots', 'Plugin installer section title' ),
488
				'changelog'    => _x( 'Changelog', 'Plugin installer section title' ),
489
				'reviews'      => _x( 'Reviews', 'Plugin installer section title' ),
490
				'other_notes'  => _x( 'Other Notes', 'Plugin installer section title' ),
491
			);
492
493
			// Sanitize HTML
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
494
//		foreach ( (array) $api->sections as $section_name => $content ) {
495
//			$api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
496
//		}
497
498
			foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
499
				if ( isset( $api->$key ) ) {
500
					$api->$key = wp_kses( $api->$key, $plugins_allowedtags );
501
				}
502
			}
503
504
			// Add after $api->slug is ready.
505
			$plugins_section_titles['features'] = __fs( 'features-and-pricing', $api->slug );
506
507
			$_tab = esc_attr( $tab );
508
509
			$section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
510
			if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
511
				$section_titles = array_keys( (array) $api->sections );
512
				$section        = array_shift( $section_titles );
513
			}
514
515
			iframe_header( __( 'Plugin Install' ) );
516
517
			$_with_banner = '';
518
519
//	var_dump($api->banners);
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
520
			if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
521
				$_with_banner = 'with-banner';
522
				$low          = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
523
				$high         = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
524
				?>
525
				<style type="text/css">
526
					#plugin-information-title.with-banner
527
					{
528
						background-image: url( <?php echo esc_url( $low ); ?> );
529
					}
530
531
					@media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
532
					{
533
						#plugin-information-title.with-banner
534
						{
535
							background-image: url( <?php echo esc_url( $high ); ?> );
536
						}
537
					}
538
				</style>
539
			<?php
540
			}
541
542
			echo '<div id="plugin-information-scrollable">';
543
			echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
544
			echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
545
546
			foreach ( (array) $api->sections as $section_name => $content ) {
547
				if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
548
					continue;
549
				}
550
551
				if ( isset( $plugins_section_titles[ $section_name ] ) ) {
552
					$title = $plugins_section_titles[ $section_name ];
553
				} else {
554
					$title = ucwords( str_replace( '_', ' ', $section_name ) );
555
				}
556
557
				$class       = ( $section_name === $section ) ? ' class="current"' : '';
558
				$href        = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
559
				$href        = esc_url( $href );
560
				$san_section = esc_attr( $section_name );
561
				echo "\t<a name='$san_section' href='$href' $class>$title</a>\n";
562
			}
563
564
			echo "</div>\n";
565
566
			?>
567
		<div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
568
			<div class="fyi">
569
				<?php if ( isset( $api->plans ) ) : ?>
570
					<div class="plugin-information-pricing">
571
						<?php foreach ($api->plans as $plan) : ?>
572
						<?php
573
							/**
574
							 * @var FS_Plugin_Plan $plan
575
							 */
576
						?>
577
						<h3 data-plan="<?php echo $plan->id ?>"><?php printf( __fs( 'x-plan', $api->slug ), $plan->title ) ?></h3>
578
						<?php if ( $api->is_paid ) : ?>
579
							<ul>
580
								<?php if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) : ?>
581
									<?php $pricing = $plan->pricing[0] ?>
582
									<li><label><?php _efs( 'price', $api->slug ) ?>
583
											: <?php echo $this->get_price_tag( $plan, $pricing ) ?></label></li>
584
								<?php else : ?>
585
									<?php $first = true;
586
									foreach ( $plan->pricing as $pricing ) : ?>
587
										<li><label><input name="pricing-<?php echo $plan->id ?>" type="radio"
588
										                  value="<?php echo $pricing->id ?>"<?php checked( $first, true ) ?>><?php
589
													switch ( $pricing->licenses ) {
590
														case '1':
591
															_efs( 'license-single-site', $api->slug );
592
															break;
593
														case null:
594
															_efs( 'license-unlimited', $api->slug );
595
															break;
596
														default:
597
															printf( __fs( 'license-x-sites', $api->slug ), $pricing->licenses );
598
															break;
599
													}
600
												?> - <?php echo $this->get_price_tag( $plan, $pricing ) ?></label></li>
601
										<?php $first = false; endforeach ?>
602
								<?php endif ?>
603
							</ul>
604
						<?php endif ?>
605
						<?php echo $this->get_plugin_cta( $api, $plan ) ?>
606
						<div style="clear:both"></div>
607
						<?php if ( $api->is_paid ) : ?>
608
							<?php if ( $plan->has_trial() ) : ?>
609
								<?php $trial_period = $this->get_trial_period( $plan ) ?>
610
								<ul class="fs-trial-terms">
611
									<li>
612
										<i class="dashicons dashicons-yes"></i><?php printf( __fs( 'no-commitment-x', $api->slug ), $trial_period ) ?>
613
									</li>
614
									<li>
615
										<i class="dashicons dashicons-yes"></i><?php printf( __fs( 'after-x-pay-as-little-y', $api->slug ), $trial_period, $this->get_price_tag( $plan, $plan->pricing[0] ) ) ?>
616
									</li>
617
								</ul>
618
							<?php endif ?>
619
						<?php endif ?>
620
					</div>
621
				<?php endforeach ?>
622
				<?php if ($api->is_paid) : ?>
623
				<?php $plan = $api->plans[0] ?>
624
				<?php $billing_cycle = $this->get_billing_cycle( $plan ) ?>
625
626
				<?php wp_enqueue_script( 'jquery' ); ?>
627
					<script type="text/javascript">
628
						(function ($) {
629
							$('.plugin-information-pricing input[type=radio]').click(function () {
630
								var checkout_url = '<?php echo esc_url_raw(add_query_arg(array(
631
								'plugin_id' => $plan->plugin_id,
632
								'billing_cycle' => $billing_cycle,
633
							), $api->checkout_link)) ?>&plan_id=' +
634
									$(this).parents('.plugin-information-pricing').find('h3').attr('data-plan') +
635
									'&pricing_id=' + $(this).val();
636
637
								$('.plugin-information-pricing .button, #plugin-information-footer .button').attr('href', checkout_url);
638
							});
639
						})(jQuery);
640
					</script>
641
				<?php endif ?>
642
				<?php endif ?>
643
				<div>
644
					<h3><?php _efs( 'details', $api->slug ) ?></h3>
645
					<ul>
646
						<?php if ( ! empty( $api->version ) ) { ?>
647
							<li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li>
648
						<?php
649
						}
650
							if ( ! empty( $api->author ) ) {
651
								?>
652
								<li>
653
									<strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
654
								</li>
655
							<?php
656
							}
657
							if ( ! empty( $api->last_updated ) ) {
658
								?>
659
								<li><strong><?php _e( 'Last Updated:' ); ?></strong> <span
660
										title="<?php echo $api->last_updated; ?>">
661
				<?php printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?>
662
			</span></li>
663
							<?php
664
							}
665
							if ( ! empty( $api->requires ) ) {
666
								?>
667
								<li>
668
									<strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php printf( __( '%s or higher' ), $api->requires ); ?>
669
								</li>
670
							<?php
671
							}
672
							if ( ! empty( $api->tested ) ) {
673
								?>
674
								<li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?>
675
								</li>
676
							<?php
677
							}
678
							if ( ! empty( $api->downloaded ) ) {
679
								?>
680
								<li>
681
									<strong><?php _e( 'Downloaded:' ); ?></strong> <?php printf( _n( '%s time', '%s times', $api->downloaded ), number_format_i18n( $api->downloaded ) ); ?>
682
								</li>
683
							<?php
684
							}
685
							if ( ! empty( $api->slug ) && empty( $api->external ) ) {
686
								?>
687
								<li><a target="_blank"
688
								       href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php _e( 'WordPress.org Plugin Page &#187;' ); ?></a>
689
								</li>
690
							<?php
691
							}
692
							if ( ! empty( $api->homepage ) ) {
693
								?>
694
								<li><a target="_blank"
695
								       href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage &#187;' ); ?></a>
696
								</li>
697
							<?php
698
							}
699
							if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) {
700
								?>
701
								<li><a target="_blank"
702
								       href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
703
								</li>
704
							<?php } ?>
705
					</ul>
706
				</div>
707
				<?php if ( ! empty( $api->rating ) ) { ?>
708
					<h3><?php _e( 'Average Rating' ); ?></h3>
709
					<?php wp_star_rating( array(
710
						'rating' => $api->rating,
711
						'type'   => 'percent',
712
						'number' => $api->num_ratings
713
					) ); ?>
714
					<small><?php printf( _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?></small>
715
				<?php
716
				}
717
718
					if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
719
						foreach ( $api->ratings as $key => $ratecount ) {
720
							// Avoid div-by-zero.
721
							$_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
722
							?>
723
							<div class="counter-container">
724
					<span class="counter-label"><a
725
							href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
726
							target="_blank"
727
							title="<?php echo esc_attr( sprintf( _n( 'Click to see reviews that provided a rating of %d star', 'Click to see reviews that provided a rating of %d stars', $key ), $key ) ); ?>"><?php printf( _n( '%d star', '%d stars', $key ), $key ); ?></a></span>
728
					<span class="counter-back">
729
						<span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span>
730
					</span>
731
								<span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
732
							</div>
733
						<?php
734
						}
735
					}
736
					if ( ! empty( $api->contributors ) ) {
737
						?>
738
						<h3><?php _e( 'Contributors' ); ?></h3>
739
						<ul class="contributors">
740
							<?php
741
								foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
742
									if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
743
										continue;
744
									}
745
									if ( empty( $contrib_username ) ) {
746
										$contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
747
									}
748
									$contrib_username = sanitize_user( $contrib_username );
749
									if ( empty( $contrib_profile ) ) {
750
										echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</li>";
751
									} else {
752
										echo "<li><a href='{$contrib_profile}' target='_blank'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</a></li>";
753
									}
754
								}
755
							?>
756
						</ul>
757
						<?php if ( ! empty( $api->donate_link ) ) { ?>
758
							<a target="_blank"
759
							   href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
760
						<?php } ?>
761
					<?php } ?>
762
			</div>
763
			<div id="section-holder" class="wrap">
764
	<?php
765
		if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
766
			echo '<div class="notice notice-warning"><p>' . '<strong>' . __( 'Warning:' ) . '</strong> ' . __( 'This plugin has not been tested with your current version of WordPress.' ) . '</p></div>';
767
		} else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
768
			echo '<div class="notice notice-warning"><p>' . '<strong>' . __( 'Warning:' ) . '</strong> ' . __( 'This plugin has not been marked as compatible with your version of WordPress.' ) . '</p></div>';
769
		}
770
771
		foreach ( (array) $api->sections as $section_name => $content ) {
772
			$content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
773
			$content = links_add_target( $content, '_blank' );
774
775
			$san_section = esc_attr( $section_name );
776
777
			$display = ( $section_name === $section ) ? 'block' : 'none';
778
779
			if ( 'description' === $section_name &&
780
			     ( ( ! $api->external && $api->wp_org_missing ) ||
781
			       ( $api->external && $api->fs_missing ) )
782
			) {
783
				$missing_notice = array(
784
					'type'    => 'error',
785
					'id'      => md5( microtime() ),
786
					'message' => __fs( ($api->is_paid ? 'paid-addon-not-deployed' : 'free-addon-not-deployed'), $api->slug ),
787
				);
788
				fs_require_template( 'admin-notice.php', $missing_notice );
789
			}
790
			echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
791
			echo $content;
792
			echo "\t</div>\n";
793
		}
794
	echo "</div>\n";
795
	echo "</div>\n";
796
	echo "</div>\n"; // #plugin-information-scrollable
797
	echo "<div id='$tab-footer'>\n";
798
799
	echo $this->get_plugin_cta( $api );
800
801
	echo "</div>\n";
802
803
	iframe_footer();
804
	exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method install_plugin_information() 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...
805
}
806
	}
807