Completed
Push — add/about-page ( d98605...b5b998 )
by
unknown
196:05 queued 187:29
created

Jetpack_About_Page::render()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
	 * Add a submenu item to the Jetpack admin menu.
31
	 *
32
	 * @return string
33
	 */
34
	public function get_page_hook() {
35
		// Add the main admin Jetpack menu.
36
		return add_submenu_page(
37
			'jetpack',
38
			esc_html__( 'About Jetpack', 'jetpack' ),
39
			esc_html__( 'About Jetpack', 'jetpack' ),
40
			'jetpack_admin_page',
41
			'jetpack_about',
42
			array( $this, 'render' )
43
		);
44
	}
45
46
	/**
47
	 * Add page action
48
	 *
49
	 * @param string $hook Hook of current page, unused.
50
	 */
51
	public function add_page_actions( $hook ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
52
		// Place the Jetpack menu item on top and others in the order they appear.
53
		add_filter( 'custom_menu_order', '__return_true' );
54
		add_filter( 'menu_order', array( $this, 'submenu_order' ) );
55
	}
56
57
	/**
58
	 * Enqueues scripts and styles for the admin page.
59
	 */
60
	public function page_admin_scripts() {
61
		wp_enqueue_style( 'plugin-install' );
62
		wp_enqueue_script( 'plugin-install' );
63
		// required for plugin modal action button functionality.
64
		wp_enqueue_script( 'updates' );
65
		// required for modal popup JS and styling.
66
		wp_enqueue_style( 'thickbox' );
67
		wp_enqueue_script( 'thickbox' );
68
	}
69
70
	/**
71
	 * Load styles for static page.
72
	 */
73
	public function additional_styles() {
74
		Jetpack_Admin_Page::load_wrapper_styles();
75
	}
76
77
	/**
78
	 * Render the page with a common top and bottom part, and page specific content
79
	 */
80
	public function render() {
81
		Jetpack_Admin_Page::wrap_ui( array( $this, 'page_render' ), array( 'show-nav' => false ) );
82
	}
83
84
	/**
85
	 * Change order of menu item so the About page menu item is below Site Stats.
86
	 *
87
	 * @param array $menu_order List of menu slugs. It's unaffected. This filter is used to reorder the Jetpack submenu items.
88
	 *
89
	 * @return array
90
	 */
91
	public function submenu_order( $menu_order ) {
92
		global $submenu;
93
94
		$stats_key = null;
95
		$about_key = null;
96
97
		foreach ( $submenu['jetpack'] as $index => $menu_item ) {
98
			if ( false !== array_search( 'stats', $menu_item, true ) ) {
99
				$stats_key = $index;
100
			}
101
			if ( false !== array_search( 'jetpack_about', $menu_item, true ) ) {
102
				$about_key = $index;
103
			}
104
		}
105
106
		if ( $stats_key && $about_key ) {
107
			$temp                             = $submenu['jetpack'][ $stats_key ];
108
			$submenu['jetpack'][ $stats_key ] = $submenu['jetpack'][ $about_key ]; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
109
			$submenu['jetpack'][ $about_key ] = $temp; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
110
		}
111
112
		return $menu_order;
113
	}
114
115
	/**
116
	 * Render the page content
117
	 */
118
	public function page_render() {
119
		?>
120
		<div class="jp-lower">
121
			<div class="jetpack-about__link-back">
122
				<a href="<?php echo esc_url( admin_url( 'admin.php?page=jetpack' ) ); ?>">
123
					<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>
124
					<?php esc_html_e( 'Back to Jetpack Dashboard', 'jetpack' ); ?>
125
				</a>
126
			</div>
127
			<div class="jetpack-about__main">
128
				<div class="jetpack-about__logo">
129
					<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">
130
					<g>
131
						<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
132
							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
133
							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
134
							s22.122-9.803,22.122-20.614V47.245z"/>
135
						<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
136
							L33.401,54.369h24.72L45.552,30.906z"/>
137
						<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
138
							c13.242,0,18.687-6.116,18.687-16.424V20.012h10.475v32.598C158.342,66.436,149.46,78,128.427,78z"/>
139
						<path d="M216.667,28.727v47.094h-10.475V28.727h-24.386v-8.715h59.245v8.715H216.667z"/>
140
						<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
141
							l22.038,38.296L390.713,63l2.599-4.692l21.786-38.296h14.331v55.81H418.955z"/>
142
						<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
143
							l-12.151,23.464h24.72L484.569,30.906z"/>
144
						<path d="M562.081,28.727v47.094h-10.474V28.727h-24.386v-8.715h59.245v8.715H562.081z"/>
145
						<path d="M638.924,28.727v47.094H628.45V28.727h-24.386v-8.715h59.245v8.715H638.924z"/>
146
						<path d="M689.118,75.821v-50.53c4.19,0,5.866-2.263,5.866-5.28h4.442v55.81H689.118z"/>
147
						<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
148
							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
149
							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
150
							L781.464,35.765z"/>
151
						<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
152
							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"/>
153
					</g>
154
					</svg>
155
				</div>
156
				<div class="jetpack-about__content">
157
					<div class="jetpack-about__images">
158
						<ul class="jetpack-about__gravatars">
159
							<?php $this->display_gravatars(); ?>
160
						</ul>
161
						<p class="meet-the-team">
162
							<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>
163
						</p>
164
					</div>
165
166
					<div class="jetpack-about__text">
167
						<p>
168
							<?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' ); ?>
169
							<a href="https://automattic.com/" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_learn_more">
170
								<?php esc_html_e( 'Learn more about us.', 'jetpack' ); ?>
171
							</a>
172
						</p>
173
						<p>
174
							<?php esc_html_e( 'We’re a distributed company with 864 Automatticians in 68 countries speaking 84 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' ); ?>
175
						</p>
176
						<p>
177
							<?php esc_html_e( 'We believe in Open Source and the vast majority of our work is available under the GPL.', 'jetpack' ); ?>
178
						</p>
179
						<p>
180
							<?php
181
								// 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().
182
								echo wp_kses(
183
									__( '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' ),
184
									array(
185
										'a' => array(
186
											'href'   => array(),
187
											'class'  => array(),
188
											'target' => array(),
189
											'rel'    => array(),
190
											'data-jptracks-name' => array(),
191
										),
192
									)
193
								);
194
							?>
195
						</p>
196
						<p>
197
							<a href="https://automattic.com/work-with-us" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_work_with_us">
198
								<?php esc_html_e( 'Come work with us', 'jetpack' ); ?>
199
							</a>
200
						</p>
201
					</div>
202
				</div>
203
			</div>
204
205
			<div class="jetpack-about__colophon">
206
				<h3><?php esc_html_e( 'Popular WordPress services by Automattic', 'jetpack' ); ?></h3>
207
				<ul class="jetpack-about__services">
208
				<?php $this->display_plugins(); ?>
209
				</ul>
210
211
				<p class="jetpack-about__services-more">
212
				<?php
213
				echo wp_kses(
214
					__( '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' ),
215
					array(
216
						'a' => array(
217
							'href'               => array(),
218
							'target'             => array(),
219
							'rel'                => array(),
220
							'class'              => array(),
221
							'data-jptracks-name' => array(),
222
						),
223
					)
224
				);
225
				?>
226
														</p>
227
			</div>
228
		</div>
229
		<?php
230
	}
231
232
	/**
233
	 * Add information cards for a8c plugins.
234
	 */
235
	public function display_plugins() {
236
		$plugins_allowedtags = array(
237
			'a'       => array(
238
				'href'   => array(),
239
				'title'  => array(),
240
				'target' => array(),
241
			),
242
			'abbr'    => array( 'title' => array() ),
243
			'acronym' => array( 'title' => array() ),
244
			'code'    => array(),
245
			'pre'     => array(),
246
			'em'      => array(),
247
			'strong'  => array(),
248
			'ul'      => array(),
249
			'ol'      => array(),
250
			'li'      => array(),
251
			'p'       => array(),
252
			'br'      => array(),
253
		);
254
255
		// slugs for plugins we want to display.
256
		$a8c_plugins = array(
257
			'woocommerce',
258
			'wp-super-cache',
259
			'wp-job-manager',
260
			'co-authors-plus',
261
		);
262
263
		// need this to access the plugins_api() function.
264
		include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
265
266
		$plugins = array();
267
		foreach ( $a8c_plugins as $slug ) {
268
			$args = array(
269
				'slug'   => $slug,
270
				'fields' => array(
271
					'added'                    => false,
272
					'author'                   => false,
273
					'author_profile'           => false,
274
					'banners'                  => false,
275
					'contributors'             => false,
276
					'donate_link'              => false,
277
					'homepage'                 => false,
278
					'reviews'                  => false,
279
					'screenshots'              => false,
280
					'support_threads'          => false,
281
					'support_threads_resolved' => false,
282
					'sections'                 => false,
283
					'tags'                     => false,
284
					'versions'                 => false,
285
286
					'compatibility'            => true,
287
					'downloaded'               => true,
288
					'downloadlink'             => true,
289
					'icons'                    => true,
290
					'last_updated'             => true,
291
					'num_ratings'              => true,
292
					'rating'                   => true,
293
					'requires'                 => true,
294
					'requires_php'             => true,
295
					'short_description'        => true,
296
					'tested'                   => true,
297
				),
298
			);
299
300
			// should probably add some error checking here too.
301
			$api       = plugins_api( 'plugin_information', $args );
302
			$plugins[] = $api;
303
		}
304
305
		foreach ( $plugins as $plugin ) {
306
			if ( is_object( $plugin ) ) {
307
				$plugin = (array) $plugin;
308
			}
309
310
			$title   = wp_kses( $plugin['name'], $plugins_allowedtags );
311
			$version = wp_kses( $plugin['version'], $plugins_allowedtags );
312
313
			$name = wp_strip_all_tags( $title . ' ' . $version );
314
315
			// Remove any HTML from the description.
316
			$description = wp_strip_all_tags( $plugin['short_description'] );
317
318
			$wp_version = get_bloginfo( 'version' );
319
320
			$compatible_php = ( empty( $plugin['requires_php'] ) || version_compare( phpversion(), $plugin['requires_php'], '>=' ) );
321
			$compatible_wp  = ( empty( $plugin['requires'] ) || version_compare( $wp_version, $plugin['requires'], '>=' ) );
322
323
			$action_links = array();
324
325
			// install button.
326
			if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
327
				$status = install_plugin_install_status( $plugin );
328
				switch ( $status['status'] ) {
329
					case 'install':
330
						if ( $status['url'] ) {
331
							if ( $compatible_php && $compatible_wp ) {
332
								$action_links[] = sprintf(
333
									'<a class="install-now button jptracks" data-slug="%s" href="%s" aria-label="%s" data-name="%s" data-jptracks-name="jetpack_about_install_button" data-jptracks-prop="%s">%s</a>',
334
									esc_attr( $plugin['slug'] ),
335
									esc_url( $status['url'] ),
336
									/* translators: %s: plugin name and version */
337
									esc_attr( sprintf( __( 'Install %s now', 'jetpack' ), $name ) ),
338
									esc_attr( $name ),
339
									esc_attr( $name ),
340
									__( 'Install Now', 'jetpack' )
341
								);
342
							} else {
343
								$action_links[] = sprintf(
344
									'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
345
									_x( 'Cannot Install', 'plugin', 'jetpack' )
346
								);
347
							}
348
						}
349
						break;
350
351
					case 'update_available':
352
						if ( $status['url'] ) {
353
							$action_links[] = sprintf(
354
								'<a class="update-now button aria-button-if-js jptracks" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s" data-jptracks-name="jetpack_about_update_button" data-jptracks-prop="%s">%s</a>',
355
								esc_attr( $status['file'] ),
356
								esc_attr( $plugin['slug'] ),
357
								esc_url( $status['url'] ),
358
								/* translators: %s: plugin name and version */
359
								esc_attr( sprintf( __( 'Update %s now', 'jetpack' ), $name ) ),
360
								esc_attr( $name ),
361
								esc_attr( $name ),
362
								__( 'Update Now', 'jetpack' )
363
							);
364
						}
365
						break;
366
367
					case 'latest_installed':
368
					case 'newer_installed':
369
						if ( is_plugin_active( $status['file'] ) ) {
370
							$action_links[] = sprintf(
371
								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
372
								_x( 'Active', 'plugin', 'jetpack' )
373
							);
374
						} elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
375
							$button_text = __( 'Activate', 'jetpack' );
376
							/* translators: %s: plugin name */
377
							$button_label = _x( 'Activate %s', 'plugin', 'jetpack' );
378
							$activate_url = add_query_arg(
379
								array(
380
									'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
381
									'action'   => 'activate',
382
									'plugin'   => $status['file'],
383
								),
384
								network_admin_url( 'plugins.php' )
385
							);
386
387
							if ( is_network_admin() ) {
388
								$button_text = __( 'Network Activate', 'jetpack' );
389
								/* translators: %s: plugin name */
390
								$button_label = _x( 'Network Activate %s', 'plugin', 'jetpack' );
391
								$activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
392
							}
393
394
							$action_links[] = sprintf(
395
								'<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>',
396
								esc_url( $activate_url ),
397
								esc_attr( sprintf( $button_label, $plugin['name'] ) ),
398
								esc_attr( $plugin['name'] ),
399
								$button_text
400
							);
401
						} else {
402
							$action_links[] = sprintf(
403
								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
404
								_x( 'Installed', 'plugin', 'jetpack' )
405
							);
406
						}
407
						break;
408
				}
409
			}
410
411
			$details_link = self_admin_url(
412
				'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
413
				'&amp;TB_iframe=true&amp;width=600&amp;height=550'
414
			);
415
416
			if ( ! empty( $plugin['icons']['svg'] ) ) {
417
				$plugin_icon_url = $plugin['icons']['svg'];
418
			} elseif ( ! empty( $plugin['icons']['2x'] ) ) {
419
				$plugin_icon_url = $plugin['icons']['2x'];
420
			} elseif ( ! empty( $plugin['icons']['1x'] ) ) {
421
				$plugin_icon_url = $plugin['icons']['1x'];
422
			} else {
423
				$plugin_icon_url = $plugin['icons']['default'];
424
			}
425
			?>
426
427
		<li class="jetpack-about__plugin plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
428
			<?php
429
			if ( ! $compatible_php || ! $compatible_wp ) {
430
				echo '<div class="notice inline notice-error notice-alt"><p>';
431
				if ( ! $compatible_php && ! $compatible_wp ) {
432
					esc_html_e( 'This plugin doesn&#8217;t work with your versions of WordPress and PHP.', 'jetpack' );
433
					if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
434
						printf(
435
							/* translators: 1: "Update WordPress" screen URL, 2: "Update PHP" page URL */
436
							' ' . 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 ) ) ),
437
							esc_url( self_admin_url( 'update-core.php' ) ),
438
							esc_url( $this->jp_get_update_php_url() )
439
						);
440
						$this->jp_update_php_annotation();
441
					} elseif ( current_user_can( 'update_core' ) ) {
442
						printf(
443
							/* translators: %s: "Update WordPress" screen URL */
444
							' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
445
							esc_url( self_admin_url( 'update-core.php' ) )
446
						);
447 View Code Duplication
					} elseif ( current_user_can( 'update_php' ) ) {
448
						printf(
449
							/* translators: %s: "Update PHP" page URL */
450
							' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
451
							esc_url( $this->jp_get_update_php_url() )
452
						);
453
						$this->jp_update_php_annotation();
454
					}
455
				} elseif ( ! $compatible_wp ) {
456
					esc_html_e( 'This plugin doesn&#8217;t work with your version of WordPress.', 'jetpack' );
457
					if ( current_user_can( 'update_core' ) ) {
458
						printf(
459
							/* translators: %s: "Update WordPress" screen URL */
460
							' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
461
							esc_url( self_admin_url( 'update-core.php' ) )
462
						);
463
					}
464 View Code Duplication
				} elseif ( ! $compatible_php ) {
465
					esc_html_e( 'This plugin doesn&#8217;t work with your version of PHP.', 'jetpack' );
466
					if ( current_user_can( 'update_php' ) ) {
467
						printf(
468
							/* translators: %s: "Update PHP" page URL */
469
							' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
470
							esc_url( $this->jp_get_update_php_url() )
471
						);
472
						$this->jp_update_php_annotation();
473
					}
474
				}
475
				echo '</p></div>';
476
			}
477
			?>
478
479
			<div class="plugin-card-top">
480
				<div class="name column-name">
481
					<h3>
482
						<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'] ); ?>">
483
						<?php echo esc_html( $title ); ?>
484
						<img src="<?php echo esc_attr( $plugin_icon_url ); ?>" class="plugin-icon" alt="">
485
						</a>
486
					</h3>
487
				</div>
488
				<div class="desc column-description">
489
					<p><?php echo esc_html( $description ); ?></p>
490
				</div>
491
492
				<div class="details-link">
493
					<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>
494
				</div>
495
			</div>
496
497
			<div class="plugin-card-bottom">
498
				<div class="meta">
499
					<?php
500
					wp_star_rating(
501
						array(
502
							'rating' => $plugin['rating'],
503
							'type'   => 'percent',
504
							'number' => $plugin['num_ratings'],
505
						)
506
					);
507
					?>
508
					<span class="num-ratings" aria-hidden="true">(<?php echo esc_html( number_format_i18n( $plugin['num_ratings'] ) ); ?> <?php esc_html_e( 'ratings', 'jetpack' ); ?>)</span>
509
					<div class="downloaded">
510
						<?php
511
						if ( $plugin['active_installs'] >= 1000000 ) {
512
							$active_installs_millions = floor( $plugin['active_installs'] / 1000000 );
513
							$active_installs_text     = sprintf(
514
								/* translators: number of millions of installs. */
515
								_nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations', 'jetpack' ),
516
								number_format_i18n( $active_installs_millions )
517
							);
518
						} elseif ( 0 === $plugin['active_installs'] ) {
519
							$active_installs_text = _x( 'Less Than 10', 'Active plugin installations', 'jetpack' );
520
						} else {
521
							$active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
522
						}
523
						/* translators: number of active installs */
524
						printf( esc_html__( '%s Active Installations', 'jetpack' ), esc_html( $active_installs_text ) );
525
						?>
526
					</div>
527
				</div>
528
529
				<div class="action-links">
530
					<?php
531
					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...
532
						// The var simply collects strings that have already been sanitized.
533
						// phpcs:ignore WordPress.Security.EscapeOutput
534
						echo '<ul class="action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
535
					}
536
					?>
537
				</div>
538
			</div>
539
		</li>
540
			<?php
541
542
		}
543
544
	}
545
546
	/**
547
	 * Fetch Gravatar hashes for public A12s from wpcom and display them as a list.
548
	 *
549
	 * @since 7.3
550
	 */
551
	public function display_gravatars() {
552
		$hashes = get_transient( 'a12s_hashes' );
553
		if ( false === $hashes ) {
554
			$response = json_decode(
555
				wp_remote_retrieve_body(
556
					wp_remote_get( 'https://public-api.wordpress.com/wpcom/v2/a11n-gravatar-hashes' )
557
				)
558
			);
559
			if ( ! empty( $response ) && is_array( $response ) ) {
560
				$hashes = array();
561
				foreach ( $response as $hash ) {
562
					$hashes[] = "https://2.gravatar.com/avatar/$hash";
563
				}
564
				if ( ! empty( $hashes ) ) {
565
					set_transient( 'a12s_hashes', $hashes, DAY_IN_SECONDS );
566
				} else {
567
					$hashes = array(
568
						'https://2.gravatar.com/avatar/5ef318426c941cbef6db5342c1356231',
569
						'https://0.gravatar.com/avatar/07adca4279691873f594d48dd7c657e1',
570
						'https://2.gravatar.com/avatar/b0b357b291ac72bc7da81b4d74430fe6',
571
						'https://1.gravatar.com/avatar/ab1f64abf81653d5a60d78a86a26bec1',
572
						'https://2.gravatar.com/avatar/eecc887dff6e1e42103590c76f215d87',
573
						'https://0.gravatar.com/avatar/987da1e668e6eb5cde64b52a477764ec',
574
						'https://1.gravatar.com/avatar/4ac90c7bc18ab89a243e6ca93bda983a',
575
						'https://1.gravatar.com/avatar/4d346581a3340e32cf93703c9ce46bd4',
576
						'https://1.gravatar.com/avatar/78c17142720e599ad7919c541124749e',
577
						'https://0.gravatar.com/avatar/9f376366854d750124dffe057dda99c9',
578
						'https://1.gravatar.com/avatar/1a33e7a69df4f675fcd799edca088ac2',
579
						'https://0.gravatar.com/avatar/30cf08c478da339285e39b5e8feb6a3f',
580
						'https://1.gravatar.com/avatar/d212b7b6c54f0ccb2c848d23440b33ba',
581
						'https://0.gravatar.com/avatar/c0ccdd53794779bcc07fcae7b79c4d80',
582
						'https://2.gravatar.com/avatar/8e6e7e85e416fd569d0f821f6fbc4c2f',
583
						'https://2.gravatar.com/avatar/ebdbd8f65be345e43b11e4487e9fc445',
584
					);
585
				}
586
			}
587
		}
588
		$output = '';
589
		foreach ( $hashes as $hash ) {
590
			$output .= '<li><img src="' . esc_url( $hash ) . '?s=150"></li>' . "\n";
591
		}
592
		echo wp_kses(
593
			$output,
594
			array(
595
				'li'  => true,
596
				'img' => array(
597
					'src' => true,
598
				),
599
			)
600
		);
601
	}
602
603
	// The following methods jp_get_update_php_url, jp_get_default_update_php_url, and jp_update_php_annotation,
604
	// are copies of functions introduced in WP 5.1
605
	// At the time of releasing this, we're still supporting WP 5.0, so we needed
606
	// to have them here to avoid fatal errors in old installations.
607
608
	/**
609
	 * Gets the URL to learn more about updating the PHP version the site is running on.
610
	 *
611
	 * This URL can be overridden by specifying an environment variable `WP_UPDATE_PHP_URL` or by using the
612
	 * {@see 'wp_update_php_url'} filter. Providing an empty string is not allowed and will result in the
613
	 * default URL being used. Furthermore the page the URL links to should preferably be localized in the
614
	 * site language.
615
	 *
616
	 * @since 5.1.0
617
	 *
618
	 * @return string URL to learn more about updating PHP.
619
	 */
620
	private function jp_get_update_php_url() {
621
		$default_url = $this->jp_get_default_update_php_url();
622
623
		$update_url = $default_url;
624
		if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
625
			$update_url = getenv( 'WP_UPDATE_PHP_URL' );
626
		}
627
628
		/**
629
		 * Filters the URL to learn more about updating the PHP version the site is running on.
630
		 *
631
		 * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
632
		 * the page the URL links to should preferably be localized in the site language.
633
		 *
634
		 * @since 5.1.0
635
		 *
636
		 * @param string $update_url URL to learn more about updating PHP.
637
		 */
638
		$update_url = apply_filters( 'wp_update_php_url', $update_url );
639
640
		if ( empty( $update_url ) ) {
641
			$update_url = $default_url;
642
		}
643
644
		return $update_url;
645
	}
646
647
	/**
648
	 * Gets the default URL to learn more about updating the PHP version the site is running on.
649
	 *
650
	 * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_php_url()} when relying on the URL.
651
	 * This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
652
	 * default one.
653
	 *
654
	 * @since 5.1.0
655
	 * @access private
656
	 *
657
	 * @return string Default URL to learn more about updating PHP.
658
	 */
659
	private function jp_get_default_update_php_url() {
660
		return _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page', 'jetpack' );
661
	}
662
663
	/**
664
	 * Prints the default annotation for the web host altering the "Update PHP" page URL.
665
	 *
666
	 * This function is to be used after {@see wp_get_update_php_url()} to display a consistent
667
	 * annotation if the web host has altered the default "Update PHP" page URL.
668
	 *
669
	 * @since 5.1.0
670
	 */
671
	private function jp_update_php_annotation() {
672
		$update_url  = $this->jp_get_update_php_url();
673
		$default_url = $this->jp_get_default_update_php_url();
674
675
		if ( $update_url === $default_url ) {
676
			return;
677
		}
678
679
		echo '<p class="description">';
680
		printf(
681
			wp_kses(
682
				/* translators: %s: default Update PHP page URL */
683
				__( 'This resource is provided by your web host, and is specific to your site. For more information, <a href="%s" target="_blank" rel="noopener noreferrer">see the official WordPress documentation</a>.', 'jetpack' ),
684
				array(
685
					'a' => array(
686
						'href' => true,
687
						'rel'  => true,
688
					),
689
				)
690
			),
691
			esc_url( $default_url )
692
		);
693
		echo '</p>';
694
	}
695
696
}
697