PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | _inc/lib/admin-pages/class-jetpack-about-page.php +605 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,605 @@
1 +<?php
2 +/**
3 + * Class for the Jetpack About Page within the wp-admin.
4 + *
5 + * @package automattic/jetpack
6 + */
7 +
8 +/**
9 + * Disable direct access and execution.
10 + */
11 +if ( ! defined( 'ABSPATH' ) ) {
12 + exit( 0 );
13 +}
14 +
15 +require_once __DIR__ . '/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 + '',
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.
57 + */
58 + public function add_page_actions( $hook ) {
59 + if ( 'admin_page_jetpack_about' === $hook ) {
60 + $this->a8c_data = $this->fetch_a8c_data();
61 + }
62 + }
63 +
64 + /**
65 + * Enqueues scripts and styles for the admin page.
66 + */
67 + public function page_admin_scripts() {
68 + wp_enqueue_style( 'plugin-install' );
69 + wp_enqueue_script( 'plugin-install' );
70 + // required for plugin modal action button functionality.
71 + wp_enqueue_script( 'updates' );
72 + // required for modal popup JS and styling.
73 + wp_enqueue_style( 'thickbox' );
74 + wp_enqueue_script( 'thickbox' );
75 + }
76 +
77 + /**
78 + * Load styles for static page.
79 + */
80 + public function additional_styles() {
81 + Jetpack_Admin_Page::load_wrapper_styles();
82 + }
83 +
84 + /**
85 + * Render the page with a common top and bottom part, and page specific content
86 + */
87 + public function render() {
88 + Jetpack_Admin_Page::wrap_ui( array( $this, 'page_render' ), array( 'show-nav' => false ) );
89 + }
90 +
91 + /**
92 + * Render the page content
93 + */
94 + public function page_render() {
95 + ?>
96 + <div class="jp-lower">
97 + <h1 class="screen-reader-text"><?php esc_html_e( 'About Jetpack', 'jetpack' ); ?></h1>
98 + <div class="jetpack-about__main">
99 + <div class="jetpack-about__logo">
100 + <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">
101 + <g>
102 + <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
103 + 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
104 + 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
105 + s22.122-9.803,22.122-20.614V47.245z"/>
106 + <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
107 + L33.401,54.369h24.72L45.552,30.906z"/>
108 + <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
109 + c13.242,0,18.687-6.116,18.687-16.424V20.012h10.475v32.598C158.342,66.436,149.46,78,128.427,78z"/>
110 + <path d="M216.667,28.727v47.094h-10.475V28.727h-24.386v-8.715h59.245v8.715H216.667z"/>
111 + <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
112 + l22.038,38.296L390.713,63l2.599-4.692l21.786-38.296h14.331v55.81H418.955z"/>
113 + <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
114 + l-12.151,23.464h24.72L484.569,30.906z"/>
115 + <path d="M562.081,28.727v47.094h-10.474V28.727h-24.386v-8.715h59.245v8.715H562.081z"/>
116 + <path d="M638.924,28.727v47.094H628.45V28.727h-24.386v-8.715h59.245v8.715H638.924z"/>
117 + <path d="M689.118,75.821v-50.53c4.19,0,5.866-2.263,5.866-5.28h4.442v55.81H689.118z"/>
118 + <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
119 + 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
120 + 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
121 + L781.464,35.765z"/>
122 + <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
123 + 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"/>
124 + </g>
125 + </svg>
126 + </div>
127 + <div class="jetpack-about__content">
128 + <div class="jetpack-about__images">
129 + <ul class="jetpack-about__gravatars">
130 + <?php $this->display_gravatars(); ?>
131 + </ul>
132 + <p class="meet-the-team">
133 + <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>
134 + <svg class="gridicons-external" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6c0 1.105-.895 2-2 2H5c-1.105 0-2-.895-2-2V7c0-1.105.895-2 2-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>
135 + </p>
136 + </div>
137 +
138 + <div class="jetpack-about__text">
139 + <p>
140 + <?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' ); ?>
141 + <a href="https://automattic.com/" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_learn_more">
142 + <?php esc_html_e( 'Learn more about us', 'jetpack' ); ?>
143 + </a>
144 + <svg class="gridicons-external" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6c0 1.105-.895 2-2 2H5c-1.105 0-2-.895-2-2V7c0-1.105.895-2 2-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>
145 + </p>
146 + <p>
147 + <?php
148 + echo esc_html(
149 + sprintf(
150 + /* translators: first placeholder is the number of Automattic employees. The second is the number of countries of origin*/
151 + __( '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' ),
152 + $this->a8c_data['a12s'],
153 + $this->a8c_data['countries'],
154 + $this->a8c_data['languages']
155 + )
156 + );
157 + ?>
158 + </p>
159 + <p>
160 + <?php esc_html_e( 'We believe in Open Source and the vast majority of our work is available under the GPL.', 'jetpack' ); ?>
161 + </p>
162 + <p>
163 + <?php
164 + // 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().
165 + echo wp_kses(
166 + __( '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><svg class="gridicons-external" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6c0 1.105-.895 2-2 2H5c-1.105 0-2-.895-2-2V7c0-1.105.895-2 2-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>', 'jetpack' ),
167 + array(
168 + 'a' => array(
169 + 'href' => array(),
170 + 'class' => array(),
171 + 'target' => array(),
172 + 'rel' => array(),
173 + 'data-jptracks-name' => array(),
174 + ),
175 + 'svg' => array(
176 + 'class' => array(),
177 + 'height' => array(),
178 + 'width' => array(),
179 + 'xmlns' => array(),
180 + 'viewbox' => array(),
181 + ),
182 + 'g' => array(),
183 + 'path' => array(
184 + 'd' => array(),
185 + ),
186 + )
187 + );
188 + ?>
189 + </p>
190 + <p>
191 + <a href="https://automattic.com/work-with-us" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_work_with_us"><?php esc_html_e( 'Come work with us', 'jetpack' ); ?>
192 + </a><svg class="gridicons-external" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6c0 1.105-.895 2-2 2H5c-1.105 0-2-.895-2-2V7c0-1.105.895-2 2-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>
193 + </p>
194 + </div>
195 + </div>
196 + </div>
197 +
198 + <div class="jetpack-about__colophon">
199 + <h3><?php esc_html_e( 'Popular WordPress services by Automattic', 'jetpack' ); ?></h3>
200 + <ul class="jetpack-about__services">
201 + <?php $this->display_plugins(); ?>
202 + </ul>
203 +
204 + <p class="jetpack-about__services-more">
205 + <?php
206 + echo wp_kses(
207 + __( 'For even more of our WordPress plugins, please take a look at <a href="https://profiles.wordpress.org/automattic/#content-plugins" target="_blank" rel="noopener noreferrer" class="jptracks" data-jptracks-name="jetpack_about_wporg_profile">our WordPress.org profile</a>.', 'jetpack' ),
208 + array(
209 + 'a' => array(
210 + 'href' => array(),
211 + 'target' => array(),
212 + 'rel' => array(),
213 + 'class' => array(),
214 + 'data-jptracks-name' => array(),
215 + ),
216 + )
217 + );
218 + ?>
219 + </p>
220 + </div>
221 + </div>
222 + <?php
223 + }
224 +
225 + /**
226 + * Add information cards for a8c plugins.
227 + */
228 + public function display_plugins() {
229 + $plugins_allowedtags = array(
230 + 'a' => array(
231 + 'href' => array(),
232 + 'title' => array(),
233 + 'target' => array(),
234 + ),
235 + 'abbr' => array( 'title' => array() ),
236 + 'acronym' => array( 'title' => array() ),
237 + 'code' => array(),
238 + 'pre' => array(),
239 + 'em' => array(),
240 + 'strong' => array(),
241 + 'ul' => array(),
242 + 'ol' => array(),
243 + 'li' => array(),
244 + 'p' => array(),
245 + 'br' => array(),
246 + );
247 +
248 + // slugs for plugins we want to display.
249 + $a8c_plugins = $this->a8c_data['featured_plugins'];
250 +
251 + // need this to access the plugins_api() function.
252 + include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
253 +
254 + $plugins = array();
255 + foreach ( $a8c_plugins as $slug ) {
256 + $args = array(
257 + 'slug' => $slug,
258 + 'fields' => array(
259 + 'added' => false,
260 + 'author' => false,
261 + 'author_profile' => false,
262 + 'banners' => false,
263 + 'contributors' => false,
264 + 'donate_link' => false,
265 + 'homepage' => false,
266 + 'reviews' => false,
267 + 'screenshots' => false,
268 + 'support_threads' => false,
269 + 'support_threads_resolved' => false,
270 + 'sections' => false,
271 + 'tags' => false,
272 + 'versions' => false,
273 +
274 + 'compatibility' => true,
275 + 'downloaded' => true,
276 + 'downloadlink' => true,
277 + 'icons' => true,
278 + 'last_updated' => true,
279 + 'num_ratings' => true,
280 + 'rating' => true,
281 + 'requires' => true,
282 + 'requires_php' => true,
283 + 'short_description' => true,
284 + 'tested' => true,
285 + ),
286 + );
287 +
288 + // should probably add some error checking here too.
289 + $api = plugins_api( 'plugin_information', $args );
290 + $plugins[] = $api;
291 + }
292 +
293 + foreach ( $plugins as $plugin ) {
294 + if ( is_object( $plugin ) ) {
295 + $plugin = (array) $plugin;
296 + }
297 +
298 + $title = wp_kses( $plugin['name'], $plugins_allowedtags );
299 + $version = wp_kses( $plugin['version'], $plugins_allowedtags );
300 +
301 + $name = wp_strip_all_tags( $title . ' ' . $version );
302 +
303 + // Remove any HTML from the description.
304 + $description = wp_strip_all_tags( $plugin['short_description'] );
305 +
306 + $wp_version = get_bloginfo( 'version' );
307 +
308 + $compatible_php = ( empty( $plugin['requires_php'] ) || version_compare( phpversion(), $plugin['requires_php'], '>=' ) );
309 + $compatible_wp = ( empty( $plugin['requires'] ) || version_compare( $wp_version, $plugin['requires'], '>=' ) );
310 +
311 + $action_links = array();
312 +
313 + // install button.
314 + if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
315 + $status = install_plugin_install_status( $plugin );
316 + switch ( $status['status'] ) {
317 + case 'install':
318 + if ( $status['url'] ) {
319 + if ( $compatible_php && $compatible_wp ) {
320 + $action_links[] = sprintf(
321 + '<a class="install-now button jptracks is-rna" 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>',
322 + esc_attr( $plugin['slug'] ),
323 + esc_url( $status['url'] ),
324 + /* translators: %s: plugin name and version */
325 + esc_attr( sprintf( __( 'Install %s now', 'jetpack' ), $name ) ),
326 + esc_attr( $name ),
327 + esc_html__( 'Install Now', 'jetpack' )
328 + );
329 + } else {
330 + $action_links[] = sprintf(
331 + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
332 + _x( 'Cannot Install', 'plugin', 'jetpack' )
333 + );
334 + }
335 + }
336 + break;
337 +
338 + case 'update_available':
339 + if ( $status['url'] ) {
340 + $action_links[] = sprintf(
341 + '<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>',
342 + esc_attr( $status['file'] ),
343 + esc_attr( $plugin['slug'] ),
344 + esc_url( $status['url'] ),
345 + /* translators: %s: plugin name and version */
346 + esc_attr( sprintf( __( 'Update %s now', 'jetpack' ), $name ) ),
347 + esc_attr( $name ),
348 + __( 'Update Now', 'jetpack' )
349 + );
350 + }
351 + break;
352 +
353 + case 'latest_installed':
354 + case 'newer_installed':
355 + if ( is_plugin_active( $status['file'] ) ) {
356 + $action_links[] = sprintf(
357 + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
358 + _x( 'Active', 'plugin', 'jetpack' )
359 + );
360 + } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
361 + $button_text = __( 'Activate', 'jetpack' );
362 + /* translators: %s: plugin name */
363 + $button_label = _x( 'Activate %s', 'plugin', 'jetpack' );
364 + $activate_url = add_query_arg(
365 + array(
366 + '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
367 + 'action' => 'activate',
368 + 'plugin' => $status['file'],
369 + ),
370 + network_admin_url( 'plugins.php' )
371 + );
372 +
373 + if ( is_network_admin() ) {
374 + $button_text = __( 'Network Activate', 'jetpack' );
375 + /* translators: %s: plugin name */
376 + $button_label = _x( 'Network Activate %s', 'plugin', 'jetpack' );
377 + $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
378 + }
379 +
380 + $action_links[] = sprintf(
381 + '<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>',
382 + esc_url( $activate_url ),
383 + esc_attr( sprintf( $button_label, $plugin['name'] ) ),
384 + esc_attr( $plugin['name'] ),
385 + $button_text
386 + );
387 + } else {
388 + $action_links[] = sprintf(
389 + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
390 + _x( 'Installed', 'plugin', 'jetpack' )
391 + );
392 + }
393 + break;
394 + }
395 + }
396 +
397 + $plugin_install = "plugin-install.php?tab=plugin-information&amp;plugin={$plugin['slug']}&amp;TB_iframe=true&amp;width=600&amp;height=550";
398 + $details_link = is_multisite()
399 + ? network_admin_url( $plugin_install )
400 + : admin_url( $plugin_install );
401 +
402 + if ( ! empty( $plugin['icons']['svg'] ) ) {
403 + $plugin_icon_url = $plugin['icons']['svg'];
404 + } elseif ( ! empty( $plugin['icons']['2x'] ) ) {
405 + $plugin_icon_url = $plugin['icons']['2x'];
406 + } elseif ( ! empty( $plugin['icons']['1x'] ) ) {
407 + $plugin_icon_url = $plugin['icons']['1x'];
408 + } else {
409 + $plugin_icon_url = $plugin['icons']['default'];
410 + }
411 + ?>
412 +
413 + <li class="jetpack-about__plugin plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
414 + <?php
415 + if ( ! $compatible_php || ! $compatible_wp ) {
416 + echo '<div class="notice inline notice-error notice-alt"><p>';
417 + if ( ! $compatible_php && ! $compatible_wp ) {
418 + esc_html_e( 'This plugin doesn&#8217;t work with your versions of WordPress and PHP.', 'jetpack' );
419 + if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
420 + printf(
421 + /* translators: 1: "Update WordPress" screen URL, 2: "Update PHP" page URL */
422 + ' ' . 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 ) ) ),
423 + esc_url( self_admin_url( 'update-core.php' ) ),
424 + esc_url( wp_get_update_php_url() )
425 + );
426 + wp_update_php_annotation();
427 + } elseif ( current_user_can( 'update_core' ) ) {
428 + printf(
429 + /* translators: %s: "Update WordPress" screen URL */
430 + ' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
431 + esc_url( self_admin_url( 'update-core.php' ) )
432 + );
433 + } elseif ( current_user_can( 'update_php' ) ) {
434 + printf(
435 + /* translators: %s: "Update PHP" page URL */
436 + ' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
437 + esc_url( wp_get_update_php_url() )
438 + );
439 + wp_update_php_annotation();
440 + }
441 + } elseif ( ! $compatible_wp ) {
442 + esc_html_e( 'This plugin doesn&#8217;t work with your version of WordPress.', 'jetpack' );
443 + if ( current_user_can( 'update_core' ) ) {
444 + printf(
445 + /* translators: %s: "Update WordPress" screen URL */
446 + ' ' . wp_kses( __( '<a href="%s">Please update WordPress</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
447 + esc_url( self_admin_url( 'update-core.php' ) )
448 + );
449 + }
450 + } elseif ( ! $compatible_php ) {
451 + esc_html_e( 'This plugin doesn&#8217;t work with your version of PHP.', 'jetpack' );
452 + if ( current_user_can( 'update_php' ) ) {
453 + printf(
454 + /* translators: %s: "Update PHP" page URL */
455 + ' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
456 + esc_url( wp_get_update_php_url() )
457 + );
458 + wp_update_php_annotation();
459 + }
460 + }
461 + echo '</p></div>';
462 + }
463 + ?>
464 +
465 + <div class="plugin-card-top">
466 + <div class="name column-name">
467 + <h3>
468 + <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'] ); ?>">
469 + <?php echo esc_html( $title ); ?>
470 + <img src="<?php echo esc_url( $plugin_icon_url ); ?>" class="plugin-icon" alt="<?php esc_attr_e( 'Plugin icon', 'jetpack' ); ?>" aria-hidden="true">
471 + </a>
472 + </h3>
473 + </div>
474 + <div class="desc column-description">
475 + <p><?php echo esc_html( $description ); ?></p>
476 + </div>
477 +
478 + <div class="details-link">
479 + <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>
480 + </div>
481 + </div>
482 +
483 + <div class="plugin-card-bottom">
484 + <div class="meta">
485 + <?php
486 + wp_star_rating(
487 + array(
488 + 'rating' => $plugin['rating'],
489 + 'type' => 'percent',
490 + 'number' => $plugin['num_ratings'],
491 + )
492 + );
493 + ?>
494 + <span class="num-ratings" aria-hidden="true">(<?php echo esc_html( number_format_i18n( $plugin['num_ratings'] ) ); ?> <?php esc_html_e( 'ratings', 'jetpack' ); ?>)</span>
495 + <div class="downloaded">
496 + <?php
497 + if ( $plugin['active_installs'] >= 1000000 ) {
498 + $active_installs_millions = floor( $plugin['active_installs'] / 1000000 );
499 + $active_installs_text = sprintf(
500 + /* translators: number of millions of installs. */
501 + _nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations', 'jetpack' ),
502 + number_format_i18n( $active_installs_millions )
503 + );
504 + } elseif ( 0 === $plugin['active_installs'] ) {
505 + $active_installs_text = _x( 'Less Than 10', 'Active plugin installations', 'jetpack' );
506 + } else {
507 + $active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
508 + }
509 + /* translators: number of active installs */
510 + printf( esc_html__( '%s Active Installations', 'jetpack' ), esc_html( $active_installs_text ) );
511 + ?>
512 + </div>
513 + </div>
514 +
515 + <div class="action-links">
516 + <?php
517 + if ( $action_links ) {
518 + // The var simply collects strings that have already been sanitized.
519 + // phpcs:ignore WordPress.Security.EscapeOutput
520 + echo '<ul class="action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
521 + }
522 + ?>
523 + </div>
524 + </div>
525 + </li>
526 + <?php
527 +
528 + }
529 + }
530 +
531 + /**
532 + * Fetch anonymous data about A12s from wpcom: total count, number of countries, languages spoken.
533 + *
534 + * @since 7.4
535 + *
536 + * @return array $data
537 + */
538 + private function fetch_a8c_data() {
539 + $data = get_transient( 'jetpack_a8c_data' );
540 + if ( false === $data ) {
541 + $data = json_decode(
542 + wp_remote_retrieve_body(
543 + wp_remote_get( 'https://public-api.wordpress.com/wpcom/v2/jetpack-about' )
544 + ),
545 + true
546 + );
547 + if ( ! empty( $data ) && is_array( $data ) ) {
548 + set_transient( 'jetpack_a8c_data', $data, WEEK_IN_SECONDS );
549 + } else {
550 + // Fallback if everything fails.
551 + $data = array(
552 + 'a12s' => 888,
553 + 'countries' => 69,
554 + 'languages' => 83,
555 + 'featured_plugins' => array(
556 + 'woocommerce',
557 + 'activitypub',
558 + 'wp-job-manager',
559 + 'wp-super-cache',
560 + ),
561 + );
562 + }
563 + }
564 + return $data;
565 + }
566 +
567 + /**
568 + * Compile and display a list of avatars for A12s that gave their permission.
569 + *
570 + * @since 7.3
571 + */
572 + public function display_gravatars() {
573 + $hashes = array(
574 + 'https://1.gravatar.com/avatar/d2ab03dbab0c97740be75f290a2e3190',
575 + 'https://2.gravatar.com/avatar/b0b357b291ac72bc7da81b4d74430fe6',
576 + 'https://2.gravatar.com/avatar/9e149207a0e0818abed0edbb1fb2d0bf',
577 + 'https://2.gravatar.com/avatar/9f376366854d750124dffe057dda99c9',
578 + 'https://1.gravatar.com/avatar/1c75d26ad0d38624f02b15accc1f20cd',
579 + 'https://1.gravatar.com/avatar/c510e69d83c7d10be4df64feeff4e46a',
580 + 'https://0.gravatar.com/avatar/88ec0dcadea38adf5f30a17e54e9b248',
581 + 'https://1.gravatar.com/avatar/1ec3571e0201a990ceca5e365e780efa',
582 + 'https://0.gravatar.com/avatar/0619d4de8aef78c81b2194ff1d164d85',
583 + 'https://0.gravatar.com/avatar/7fdcad31a04def0ab9583af475c9036c',
584 + 'https://0.gravatar.com/avatar/b3618d70c63bbc5cc7caee0beded5ff0',
585 + 'https://1.gravatar.com/avatar/4d346581a3340e32cf93703c9ce46bd4',
586 + 'https://2.gravatar.com/avatar/9c2f6b95a00dfccfadc6a912a2b859ba',
587 + 'https://1.gravatar.com/avatar/1a33e7a69df4f675fcd799edca088ac2',
588 + 'https://2.gravatar.com/avatar/d5dc443845c134f365519568d5d80e62',
589 + 'https://0.gravatar.com/avatar/c0ccdd53794779bcc07fcae7b79c4d80',
590 + );
591 + $output = '';
592 + foreach ( $hashes as $hash ) {
593 + $output .= '<li><img src="' . esc_url( $hash ) . '?s=150"></li>' . "\n";
594 + }
595 + echo wp_kses(
596 + $output,
597 + array(
598 + 'li' => true,
599 + 'img' => array(
600 + 'src' => true,
601 + ),
602 + )
603 + );
604 + }
605 +}