Completed
Push — update/videopress-transcode-al... ( ffe79d...2d3973 )
by Kirk
13:06 queued 05:54
created

Jetpack_About_Page   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 578
Duplicated Lines 4.33 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 25
loc 578
rs 8.4
c 0
b 0
f 0
wmc 50
lcom 1
cbo 1

9 Methods

Rating   Name   Duplication   Size   Complexity  
A get_page_hook() 0 11 1
A add_page_actions() 0 3 1
A page_admin_scripts() 0 9 1
A additional_styles() 0 3 1
A render() 0 3 1
B page_render() 0 123 1
F display_plugins() 25 303 38
A fetch_a8c_data() 0 28 4
A display_gravatars() 0 33 2

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 Jetpack_About_Page 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 Jetpack_About_Page, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class for the Jetpack About Page within the wp-admin.
4
 *
5
 * @package Jetpack
6
 */
7
8
/**
9
 * Disable direct access and execution.
10
 */
11
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
require_once 'class.jetpack-admin-page.php';
16
17
/**
18
 * Builds the landing page and its menu.
19
 */
20
class Jetpack_About_Page extends Jetpack_Admin_Page {
21
22
	/**
23
	 * Show the settings page only when Jetpack is connected or in dev mode.
24
	 *
25
	 * @var bool If the page should be shown.
26
	 */
27
	protected $dont_show_if_not_active = true;
28
29
	/**
30
	 * Anonymous info about a12s. The method fetch_a8c_data() stores the response from wpcom here.
31
	 *
32
	 * @var array
33
	 */
34
	private $a8c_data = null;
35
36
	/**
37
	 * Add a submenu item to the Jetpack admin menu.
38
	 *
39
	 * @return string
40
	 */
41
	public function get_page_hook() {
42
		// Add the main admin Jetpack menu.
43
		return add_submenu_page(
44
			null,
45
			esc_html__( 'About Jetpack', 'jetpack' ),
46
			'',
47
			'jetpack_admin_page',
48
			'jetpack_about',
49
			array( $this, 'render' )
50
		);
51
	}
52
53
	/**
54
	 * Add page action
55
	 *
56
	 * @param string $hook Hook of current page, unused.
57
	 */
58
	public function add_page_actions( $hook ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
59
		$this->a8c_data = $this->fetch_a8c_data();
60
	}
61
62
	/**
63
	 * Enqueues scripts and styles for the admin page.
64
	 */
65
	public function page_admin_scripts() {
66
		wp_enqueue_style( 'plugin-install' );
67
		wp_enqueue_script( 'plugin-install' );
68
		// required for plugin modal action button functionality.
69
		wp_enqueue_script( 'updates' );
70
		// required for modal popup JS and styling.
71
		wp_enqueue_style( 'thickbox' );
72
		wp_enqueue_script( 'thickbox' );
73
	}
74
75
	/**
76
	 * Load styles for static page.
77
	 */
78
	public function additional_styles() {
79
		Jetpack_Admin_Page::load_wrapper_styles();
80
	}
81
82
	/**
83
	 * Render the page with a common top and bottom part, and page specific content
84
	 */
85
	public function render() {
86
		Jetpack_Admin_Page::wrap_ui( array( $this, 'page_render' ), array( 'show-nav' => false ) );
87
	}
88
89
	/**
90
	 * Render the page content
91
	 */
92
	public function page_render() {
93
		?>
94
		<div class="jp-lower">
95
			<div class="jetpack-about__link-back">
96
				<a href="<?php echo esc_url( admin_url( 'admin.php?page=jetpack' ) ); ?>">
97
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="0" fill="none" width="24" height="24"/><g><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></g></svg>
98
					<?php esc_html_e( 'Back to Jetpack Dashboard', 'jetpack' ); ?>
99
				</a>
100
			</div>
101
			<div class="jetpack-about__main">
102
				<div class="jetpack-about__logo">
103
					<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 800 96" style="enable-background:new 0 0 800 96;" xml:space="preserve">
104
					<g>
105
						<path style="fill: #39c;" d="M292.922,78c-19.777,0-32.598-14.245-32.598-29.078V47.08c0-15.086,12.821-29.08,32.598-29.08
106
							c19.861,0,32.682,13.994,32.682,29.08v1.843C325.604,63.755,312.783,78,292.922,78z M315.044,47.245
107
							c0-10.808-7.877-20.447-22.122-20.447s-22.04,9.639-22.04,20.447v1.341c0,10.811,7.795,20.614,22.04,20.614
108
							s22.122-9.803,22.122-20.614V47.245z"/>
109
						<path d="M69.602,75.821l-7.374-13.826H29.463l-7.124,13.826H11.277l30.167-55.81h8.715l30.671,55.81H69.602z M45.552,30.906
110
							L33.401,54.369h24.72L45.552,30.906z"/>
111
						<path d="M128.427,78c-20.028,0-29.329-10.894-29.329-25.391V20.012h10.391v32.765c0,10.308,6.788,16.424,19.692,16.424
112
							c13.242,0,18.687-6.116,18.687-16.424V20.012h10.475v32.598C158.342,66.436,149.46,78,128.427,78z"/>
113
						<path d="M216.667,28.727v47.094h-10.475V28.727h-24.386v-8.715h59.245v8.715H216.667z"/>
114
						<path d="M418.955,75.821V31.659l-2.766,4.861l-23.379,39.301h-5.112L364.569,36.52l-2.765-4.861v44.162h-10.224v-55.81h14.497
115
							l22.038,38.296L390.713,63l2.599-4.692l21.786-38.296h14.331v55.81H418.955z"/>
116
						<path d="M508.619,75.821l-7.374-13.826H468.48l-7.123,13.826h-11.061l30.167-55.81h8.715l30.669,55.81H508.619z M484.569,30.906
117
							l-12.151,23.464h24.72L484.569,30.906z"/>
118
						<path d="M562.081,28.727v47.094h-10.474V28.727h-24.386v-8.715h59.245v8.715H562.081z"/>
119
						<path d="M638.924,28.727v47.094H628.45V28.727h-24.386v-8.715h59.245v8.715H638.924z"/>
120
						<path d="M689.118,75.821v-50.53c4.19,0,5.866-2.263,5.866-5.28h4.442v55.81H689.118z"/>
121
						<path d="M781.464,35.765c-5.028-4.609-12.402-8.967-22.374-8.967c-14.916,0-23.296,10.225-23.296,20.867v1.089
122
							c0,10.558,8.464,20.445,24.05,20.445c9.303,0,17.012-4.441,21.872-8.965L788,66.854C781.883,72.887,771.492,78,759.174,78
123
							c-21.118,0-33.939-13.743-33.939-28.828v-1.843c0-15.084,13.993-29.329,34.44-29.329c11.816,0,22.541,4.944,28.324,11.146
124
							L781.464,35.765z"/>
125
						<path d="M299.82,37.417c1.889,1.218,2.418,3.749,1.192,5.648l-9.553,14.797c-1.226,1.901-3.752,2.452-5.637,1.234l0,0
126
							c-1.886-1.22-2.421-3.745-1.192-5.647l9.553-14.797C295.41,36.753,297.935,36.201,299.82,37.417L299.82,37.417z"/>
127
					</g>
128
					</svg>
129
				</div>
130
				<div class="jetpack-about__content">
131
					<div class="jetpack-about__images">
132
						<ul class="jetpack-about__gravatars">
133
							<?php $this->display_gravatars(); ?>
134
						</ul>
135
						<p class="meet-the-team">
136
							<a href="https://automattic.com/about/" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_meet_the_team"><?php esc_html_e( 'Meet the Automattic team', 'jetpack' ); ?></a>
137
						</p>
138
					</div>
139
140
					<div class="jetpack-about__text">
141
						<p>
142
							<?php esc_html_e( 'We are the people behind WordPress.com, WooCommerce, Jetpack, Simplenote, Longreads, VaultPress, Akismet, Gravatar, Crowdsignal, Cloudup, and more. We believe in making the web a better place.', 'jetpack' ); ?>
143
							<a href="https://automattic.com/" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_learn_more">
144
								<?php esc_html_e( 'Learn more about us.', 'jetpack' ); ?>
145
							</a>
146
						</p>
147
						<p>
148
							<?php
149
							echo esc_html(
150
								sprintf(
151
									/* translators: first placeholder is the number of Automattic employees. The second is the number of countries of origin*/
152
									__( 'We’re a distributed company with over %1$s Automatticians in more than %2$s countries speaking at least %3$s different languages. Our common goal is to democratize publishing so that anyone with a story can tell it, regardless of income, gender, politics, language, or where they live in the world.', 'jetpack' ),
153
									$this->a8c_data['a12s'],
154
									$this->a8c_data['countries'],
155
									$this->a8c_data['languages']
156
								)
157
							);
158
							?>
159
						</p>
160
						<p>
161
							<?php esc_html_e( 'We believe in Open Source and the vast majority of our work is available under the GPL.', 'jetpack' ); ?>
162
						</p>
163
						<p>
164
							<?php
165
								// Maybe use printf() because we'll want to escape the string but still allow for the link, so we can't use esc_html_e().
166
								echo wp_kses(
167
									__( 'We strive to live by the <a href="https://automattic.com/creed/" target="_blank" class="jptracks" data-jptracks-name="jetpack_about_creed" rel="noopener noreferrer">Automattic Creed</a>.', 'jetpack' ),
168
									array(
169
										'a' => array(
170
											'href'   => array(),
171
											'class'  => array(),
172
											'target' => array(),
173
											'rel'    => array(),
174
											'data-jptracks-name' => array(),
175
										),
176
									)
177
								);
178
							?>
179
						</p>
180
						<p>
181
							<a href="https://automattic.com/work-with-us" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_work_with_us">
182
								<?php esc_html_e( 'Come work with us', 'jetpack' ); ?>
183
							</a>
184
						</p>
185
					</div>
186
				</div>
187
			</div>
188
189
			<div class="jetpack-about__colophon">
190
				<h3><?php esc_html_e( 'Popular WordPress services by Automattic', 'jetpack' ); ?></h3>
191
				<ul class="jetpack-about__services">
192
				<?php $this->display_plugins(); ?>
193
				</ul>
194
195
				<p class="jetpack-about__services-more">
196
				<?php
197
				echo wp_kses(
198
					__( 'For even more of our WordPress plugins, please <a href="https://profiles.wordpress.org/automattic/#content-plugins" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_wporg_profile">take a look at our WordPress.org profile</a>.', 'jetpack' ),
199
					array(
200
						'a' => array(
201
							'href'               => array(),
202
							'target'             => array(),
203
							'rel'                => array(),
204
							'class'              => array(),
205
							'data-jptracks-name' => array(),
206
						),
207
					)
208
				);
209
				?>
210
														</p>
211
			</div>
212
		</div>
213
		<?php
214
	}
215
216
	/**
217
	 * Add information cards for a8c plugins.
218
	 */
219
	public function display_plugins() {
220
		$plugins_allowedtags = array(
221
			'a'       => array(
222
				'href'   => array(),
223
				'title'  => array(),
224
				'target' => array(),
225
			),
226
			'abbr'    => array( 'title' => array() ),
227
			'acronym' => array( 'title' => array() ),
228
			'code'    => array(),
229
			'pre'     => array(),
230
			'em'      => array(),
231
			'strong'  => array(),
232
			'ul'      => array(),
233
			'ol'      => array(),
234
			'li'      => array(),
235
			'p'       => array(),
236
			'br'      => array(),
237
		);
238
239
		// slugs for plugins we want to display.
240
		$a8c_plugins = $this->a8c_data['featured_plugins'];
241
242
		// need this to access the plugins_api() function.
243
		include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
244
245
		$plugins = array();
246
		foreach ( $a8c_plugins as $slug ) {
247
			$args = array(
248
				'slug'   => $slug,
249
				'fields' => array(
250
					'added'                    => false,
251
					'author'                   => false,
252
					'author_profile'           => false,
253
					'banners'                  => false,
254
					'contributors'             => false,
255
					'donate_link'              => false,
256
					'homepage'                 => false,
257
					'reviews'                  => false,
258
					'screenshots'              => false,
259
					'support_threads'          => false,
260
					'support_threads_resolved' => false,
261
					'sections'                 => false,
262
					'tags'                     => false,
263
					'versions'                 => false,
264
265
					'compatibility'            => true,
266
					'downloaded'               => true,
267
					'downloadlink'             => true,
268
					'icons'                    => true,
269
					'last_updated'             => true,
270
					'num_ratings'              => true,
271
					'rating'                   => true,
272
					'requires'                 => true,
273
					'requires_php'             => true,
274
					'short_description'        => true,
275
					'tested'                   => true,
276
				),
277
			);
278
279
			// should probably add some error checking here too.
280
			$api       = plugins_api( 'plugin_information', $args );
281
			$plugins[] = $api;
282
		}
283
284
		foreach ( $plugins as $plugin ) {
285
			if ( is_object( $plugin ) ) {
286
				$plugin = (array) $plugin;
287
			}
288
289
			$title   = wp_kses( $plugin['name'], $plugins_allowedtags );
290
			$version = wp_kses( $plugin['version'], $plugins_allowedtags );
291
292
			$name = wp_strip_all_tags( $title . ' ' . $version );
293
294
			// Remove any HTML from the description.
295
			$description = wp_strip_all_tags( $plugin['short_description'] );
296
297
			$wp_version = get_bloginfo( 'version' );
298
299
			$compatible_php = ( empty( $plugin['requires_php'] ) || version_compare( phpversion(), $plugin['requires_php'], '>=' ) );
300
			$compatible_wp  = ( empty( $plugin['requires'] ) || version_compare( $wp_version, $plugin['requires'], '>=' ) );
301
302
			$action_links = array();
303
304
			// install button.
305
			if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
306
				$status = install_plugin_install_status( $plugin );
307
				switch ( $status['status'] ) {
308
					case 'install':
309
						if ( $status['url'] ) {
310
							if ( $compatible_php && $compatible_wp ) {
311
								$action_links[] = sprintf(
312
									'<a class="install-now button jptracks" data-slug="%1$s" href="%2$s" aria-label="%3$s" data-name="%4$s" data-jptracks-name="jetpack_about_install_button" data-jptracks-prop="%4$s">%5$s</a>',
313
									esc_attr( $plugin['slug'] ),
314
									esc_url( $status['url'] ),
315
									/* translators: %s: plugin name and version */
316
									esc_attr( sprintf( __( 'Install %s now', 'jetpack' ), $name ) ),
317
									esc_attr( $name ),
318
									esc_html__( 'Install Now', 'jetpack' )
319
								);
320
							} else {
321
								$action_links[] = sprintf(
322
									'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
323
									_x( 'Cannot Install', 'plugin', 'jetpack' )
324
								);
325
							}
326
						}
327
						break;
328
329
					case 'update_available':
330
						if ( $status['url'] ) {
331
							$action_links[] = sprintf(
332
								'<a class="update-now button aria-button-if-js jptracks" data-plugin="%1$s" data-slug="%2$s" href="%3$s" aria-label="%4$s" data-name="%5$s" data-jptracks-name="jetpack_about_update_button" data-jptracks-prop="%5$s">%6$s</a>',
333
								esc_attr( $status['file'] ),
334
								esc_attr( $plugin['slug'] ),
335
								esc_url( $status['url'] ),
336
								/* translators: %s: plugin name and version */
337
								esc_attr( sprintf( __( 'Update %s now', 'jetpack' ), $name ) ),
338
								esc_attr( $name ),
339
								__( 'Update Now', 'jetpack' )
340
							);
341
						}
342
						break;
343
344
					case 'latest_installed':
345
					case 'newer_installed':
346
						if ( is_plugin_active( $status['file'] ) ) {
347
							$action_links[] = sprintf(
348
								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
349
								_x( 'Active', 'plugin', 'jetpack' )
350
							);
351
						} elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
352
							$button_text = __( 'Activate', 'jetpack' );
353
							/* translators: %s: plugin name */
354
							$button_label = _x( 'Activate %s', 'plugin', 'jetpack' );
355
							$activate_url = add_query_arg(
356
								array(
357
									'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
358
									'action'   => 'activate',
359
									'plugin'   => $status['file'],
360
								),
361
								network_admin_url( 'plugins.php' )
362
							);
363
364
							if ( is_network_admin() ) {
365
								$button_text = __( 'Network Activate', 'jetpack' );
366
								/* translators: %s: plugin name */
367
								$button_label = _x( 'Network Activate %s', 'plugin', 'jetpack' );
368
								$activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
369
							}
370
371
							$action_links[] = sprintf(
372
								'<a href="%1$s" class="button activate-now" aria-label="%2$s" data-jptracks-name="jetpack_about_activate_button" data-jptracks-prop="%3$s">%4$s</a>',
373
								esc_url( $activate_url ),
374
								esc_attr( sprintf( $button_label, $plugin['name'] ) ),
375
								esc_attr( $plugin['name'] ),
376
								$button_text
377
							);
378
						} else {
379
							$action_links[] = sprintf(
380
								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
381
								_x( 'Installed', 'plugin', 'jetpack' )
382
							);
383
						}
384
						break;
385
				}
386
			}
387
388
			$plugin_install = "plugin-install.php?tab=plugin-information&amp;plugin={$plugin['slug']}&amp;TB_iframe=true&amp;width=600&amp;height=550";
389
			$details_link   = is_multisite()
390
				? network_admin_url( $plugin_install )
391
				: admin_url( $plugin_install );
392
393
			if ( ! empty( $plugin['icons']['svg'] ) ) {
394
				$plugin_icon_url = $plugin['icons']['svg'];
395
			} elseif ( ! empty( $plugin['icons']['2x'] ) ) {
396
				$plugin_icon_url = $plugin['icons']['2x'];
397
			} elseif ( ! empty( $plugin['icons']['1x'] ) ) {
398
				$plugin_icon_url = $plugin['icons']['1x'];
399
			} else {
400
				$plugin_icon_url = $plugin['icons']['default'];
401
			}
402
			?>
403
404
		<li class="jetpack-about__plugin plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
405
			<?php
406
			if ( ! $compatible_php || ! $compatible_wp ) {
407
				echo '<div class="notice inline notice-error notice-alt"><p>';
408
				if ( ! $compatible_php && ! $compatible_wp ) {
409
					esc_html_e( 'This plugin doesn&#8217;t work with your versions of WordPress and PHP.', 'jetpack' );
410
					if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
411
						printf(
412
							/* translators: 1: "Update WordPress" screen URL, 2: "Update PHP" page URL */
413
							' ' . wp_kses( __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
414
							esc_url( self_admin_url( 'update-core.php' ) ),
415
							esc_url( wp_get_update_php_url() )
416
						);
417
						wp_update_php_annotation();
418 View Code Duplication
					} elseif ( current_user_can( 'update_core' ) ) {
419
						printf(
420
							/* translators: %s: "Update WordPress" screen URL */
421
							' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
422
							esc_url( self_admin_url( 'update-core.php' ) )
423
						);
424
					} elseif ( current_user_can( 'update_php' ) ) {
425
						printf(
426
							/* translators: %s: "Update PHP" page URL */
427
							' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
428
							esc_url( wp_get_update_php_url() )
429
						);
430
						wp_update_php_annotation();
431
					}
432
				} elseif ( ! $compatible_wp ) {
433
					esc_html_e( 'This plugin doesn&#8217;t work with your version of WordPress.', 'jetpack' );
434 View Code Duplication
					if ( current_user_can( 'update_core' ) ) {
435
						printf(
436
							/* translators: %s: "Update WordPress" screen URL */
437
							' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
438
							esc_url( self_admin_url( 'update-core.php' ) )
439
						);
440
					}
441 View Code Duplication
				} elseif ( ! $compatible_php ) {
442
					esc_html_e( 'This plugin doesn&#8217;t work with your version of PHP.', 'jetpack' );
443
					if ( current_user_can( 'update_php' ) ) {
444
						printf(
445
							/* translators: %s: "Update PHP" page URL */
446
							' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
447
							esc_url( wp_get_update_php_url() )
448
						);
449
						wp_update_php_annotation();
450
					}
451
				}
452
				echo '</p></div>';
453
			}
454
			?>
455
456
			<div class="plugin-card-top">
457
				<div class="name column-name">
458
					<h3>
459
						<a href="<?php echo esc_url( $details_link ); ?>" class="jptracks thickbox open-plugin-details-modal" data-jptracks-name="jetpack_about_plugin_modal" data-jptracks-prop="<?php echo esc_attr( $plugin['slug'] ); ?>">
460
						<?php echo esc_html( $title ); ?>
461
						<img src="<?php echo esc_url( $plugin_icon_url ); ?>" class="plugin-icon" alt="<?php esc_attr_e( 'Plugin icon', 'jetpack' ); ?>" aria-hidden="true">
462
						</a>
463
					</h3>
464
				</div>
465
				<div class="desc column-description">
466
					<p><?php echo esc_html( $description ); ?></p>
467
				</div>
468
469
				<div class="details-link">
470
					<a class="jptracks thickbox open-plugin-details-modal" href="<?php echo esc_url( $details_link ); ?>" data-jptracks-name="jetpack_about_plugin_details_modal" data-jptracks-prop="<?php echo esc_attr( $plugin['slug'] ); ?>"><?php esc_html_e( 'More Details', 'jetpack' ); ?></a>
471
				</div>
472
			</div>
473
474
			<div class="plugin-card-bottom">
475
				<div class="meta">
476
					<?php
477
					wp_star_rating(
478
						array(
479
							'rating' => $plugin['rating'],
480
							'type'   => 'percent',
481
							'number' => $plugin['num_ratings'],
482
						)
483
					);
484
					?>
485
					<span class="num-ratings" aria-hidden="true">(<?php echo esc_html( number_format_i18n( $plugin['num_ratings'] ) ); ?> <?php esc_html_e( 'ratings', 'jetpack' ); ?>)</span>
486
					<div class="downloaded">
487
						<?php
488
						if ( $plugin['active_installs'] >= 1000000 ) {
489
							$active_installs_millions = floor( $plugin['active_installs'] / 1000000 );
490
							$active_installs_text     = sprintf(
491
								/* translators: number of millions of installs. */
492
								_nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations', 'jetpack' ),
493
								number_format_i18n( $active_installs_millions )
494
							);
495
						} elseif ( 0 === $plugin['active_installs'] ) {
496
							$active_installs_text = _x( 'Less Than 10', 'Active plugin installations', 'jetpack' );
497
						} else {
498
							$active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
499
						}
500
						/* translators: number of active installs */
501
						printf( esc_html__( '%s Active Installations', 'jetpack' ), esc_html( $active_installs_text ) );
502
						?>
503
					</div>
504
				</div>
505
506
				<div class="action-links">
507
					<?php
508
					if ( $action_links ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $action_links of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
509
						// The var simply collects strings that have already been sanitized.
510
						// phpcs:ignore WordPress.Security.EscapeOutput
511
						echo '<ul class="action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
512
					}
513
					?>
514
				</div>
515
			</div>
516
		</li>
517
			<?php
518
519
		}
520
521
	}
522
523
	/**
524
	 * Fetch anonymous data about A12s from wpcom: total count, number of countries, languages spoken.
525
	 *
526
	 * @since 7.4
527
	 *
528
	 * @return array $data
529
	 */
530
	private function fetch_a8c_data() {
531
		$data = get_transient( 'jetpack_a8c_data' );
532
		if ( false === $data ) {
533
			$data = json_decode(
534
				wp_remote_retrieve_body(
535
					wp_remote_get( 'https://public-api.wordpress.com/wpcom/v2/jetpack-about' )
536
				),
537
				true
538
			);
539
			if ( ! empty( $data ) && is_array( $data ) ) {
540
				set_transient( 'jetpack_a8c_data', $data, DAY_IN_SECONDS );
541
			} else {
542
				// Fallback if everything fails.
543
				$data = array(
544
					'a12s'             => 888,
545
					'countries'        => 69,
546
					'languages'        => 83,
547
					'featured_plugins' => array(
548
						'woocommerce',
549
						'wp-super-cache',
550
						'wp-job-manager',
551
						'co-authors-plus',
552
					),
553
				);
554
			}
555
		}
556
		return $data;
557
	}
558
559
	/**
560
	 * Compile and display a list of avatars for A12s that gave their permission.
561
	 *
562
	 * @since 7.3
563
	 */
564
	public function display_gravatars() {
565
		$hashes = array(
566
			'https://1.gravatar.com/avatar/d2ab03dbab0c97740be75f290a2e3190',
567
			'https://2.gravatar.com/avatar/b0b357b291ac72bc7da81b4d74430fe6',
568
			'https://2.gravatar.com/avatar/9e149207a0e0818abed0edbb1fb2d0bf',
569
			'https://2.gravatar.com/avatar/9f376366854d750124dffe057dda99c9',
570
			'https://1.gravatar.com/avatar/1c75d26ad0d38624f02b15accc1f20cd',
571
			'https://1.gravatar.com/avatar/c510e69d83c7d10be4df64feeff4e46a',
572
			'https://0.gravatar.com/avatar/88ec0dcadea38adf5f30a17e54e9b248',
573
			'https://1.gravatar.com/avatar/bc45834430c5b0936d76e3f468f9ca57',
574
			'https://0.gravatar.com/avatar/0619d4de8aef78c81b2194ff1d164d85',
575
			'https://0.gravatar.com/avatar/72a638c2520ea177976e8eafb201a82f',
576
			'https://0.gravatar.com/avatar/b3618d70c63bbc5cc7caee0beded5ff0',
577
			'https://1.gravatar.com/avatar/4d346581a3340e32cf93703c9ce46bd4',
578
			'https://2.gravatar.com/avatar/9c2f6b95a00dfccfadc6a912a2b859ba',
579
			'https://1.gravatar.com/avatar/1a33e7a69df4f675fcd799edca088ac2',
580
			'https://2.gravatar.com/avatar/d5dc443845c134f365519568d5d80e62',
581
			'https://0.gravatar.com/avatar/c0ccdd53794779bcc07fcae7b79c4d80',
582
		);
583
		$output = '';
584
		foreach ( $hashes as $hash ) {
585
			$output .= '<li><img src="' . esc_url( $hash ) . '?s=150"></li>' . "\n";
586
		}
587
		echo wp_kses(
588
			$output,
589
			array(
590
				'li'  => true,
591
				'img' => array(
592
					'src' => true,
593
				),
594
			)
595
		);
596
	}
597
}
598