PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.1.3
Jetpack – WP Security, Backup, Speed, & Growth v12.1.3
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 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / class.jetpack-modules-list-table.php
jetpack Last commit date
3rd-party 3 years ago _inc 3 years ago css 3 years ago extensions 3 years ago images 3 years ago jetpack_vendor 15 hours ago json-endpoints 3 years ago modules 1 year ago sal 3 years ago src 3 years ago vendor 3 years ago views 3 years ago CHANGELOG.md 3 years ago LICENSE.txt 5 years ago SECURITY.md 5 years ago class-jetpack-connection-status.php 5 years ago class-jetpack-connection-widget.php 3 years ago class-jetpack-gallery-settings.php 3 years ago class-jetpack-pre-connection-jitms.php 4 years ago class-jetpack-recommendations-banner.php 3 years ago class-jetpack-stats-dashboard-widget.php 3 years ago class-jetpack-wizard-banner.php 5 years ago class-jetpack-xmlrpc-methods.php 3 years ago class.frame-nonce-preview.php 4 years ago class.jetpack-admin.php 3 years ago class.jetpack-affiliate.php 4 years ago class.jetpack-autoupdate.php 3 years ago class.jetpack-bbpress-json-api.compat.php 5 years ago class.jetpack-cli.php 3 years ago class.jetpack-client-server.php 4 years ago class.jetpack-connection-banner.php 3 years ago class.jetpack-data.php 5 years ago class.jetpack-gutenberg.php 3 years ago class.jetpack-heartbeat.php 4 years ago class.jetpack-idc.php 5 years ago class.jetpack-modules-list-table.php 3 years ago class.jetpack-network-sites-list-table.php 4 years ago class.jetpack-network.php 3 years ago class.jetpack-plan.php 3 years ago class.jetpack-post-images.php 3 years ago class.jetpack-twitter-cards.php 3 years ago class.jetpack-user-agent.php 3 years ago class.jetpack.php 3 years ago class.json-api-endpoints.php 3 years ago class.json-api.php 3 years ago class.photon.php 3 years ago composer.json 3 years ago enhanced-open-graph.php 3 years ago functions.compat.php 4 years ago functions.cookies.php 5 years ago functions.global.php 3 years ago functions.is-mobile.php 3 years ago functions.opengraph.php 3 years ago functions.photon.php 3 years ago jetpack.php 15 hours ago json-api-config.php 3 years ago json-endpoints.php 3 years ago load-jetpack.php 3 years ago locales.php 4 years ago readme.txt 15 hours ago uninstall.php 5 years ago wpml-config.xml 4 years ago
class.jetpack-modules-list-table.php
475 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Jetpack modules list table.
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Assets;
9
10 if ( ! class_exists( 'WP_List_Table' ) ) {
11 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
12 }
13
14 /**
15 * Jetpack modules list table.
16 */
17 class Jetpack_Modules_List_Table extends WP_List_Table {
18
19 /** Constructor. */
20 public function __construct() {
21 parent::__construct();
22
23 Jetpack::init();
24
25 if ( $this->compat_fields && is_array( $this->compat_fields ) ) {
26 array_push( $this->compat_fields, 'all_items' );
27 }
28
29 /**
30 * Filters the list of modules available to be displayed in the Jetpack Settings screen.
31 *
32 * @since 3.0.0
33 *
34 * @param array $modules Array of Jetpack modules.
35 */
36 $this->all_items = apply_filters( 'jetpack_modules_list_table_items', Jetpack_Admin::init()->get_modules() );
37 $this->items = $this->all_items;
38 $this->items = $this->filter_displayed_table_items( $this->items );
39 $this->_column_headers = array( $this->get_columns(), array(), array(), 'name' );
40 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce: This is a view, not a model or controller. InputNotSanitized: Sanitized below via `$this->module_info_check()`.
41 $modal_info = isset( $_GET['info'] ) ? wp_unslash( $_GET['info'] ) : false;
42
43 // Adding in a hidden h1 heading for screen-readers.
44 ?>
45 <h1 class="screen-reader-text"><?php esc_html_e( 'Jetpack Modules List', 'jetpack' ); ?></h1>
46 <?php
47
48 wp_register_script(
49 'models.jetpack-modules',
50 Assets::get_file_url_for_environment(
51 '_inc/build/jetpack-modules.models.min.js',
52 '_inc/jetpack-modules.models.js'
53 ),
54 array( 'jquery', 'backbone', 'underscore' ),
55 JETPACK__VERSION,
56 false // @todo Can this be put in the footer?
57 );
58 wp_register_script(
59 'views.jetpack-modules',
60 Assets::get_file_url_for_environment(
61 '_inc/build/jetpack-modules.views.min.js',
62 '_inc/jetpack-modules.views.js'
63 ),
64 array( 'jquery', 'backbone', 'underscore', 'wp-util' ),
65 JETPACK__VERSION,
66 false // @todo Can this be put in the footer?
67 );
68 wp_register_script(
69 'jetpack-modules-list-table',
70 Assets::get_file_url_for_environment(
71 '_inc/build/jetpack-modules.min.js',
72 '_inc/jetpack-modules.js'
73 ),
74 array(
75 'views.jetpack-modules',
76 'models.jetpack-modules',
77 'jquery',
78 ),
79 JETPACK__VERSION,
80 true
81 );
82
83 wp_localize_script(
84 'jetpack-modules-list-table',
85 'jetpackModulesData',
86 array(
87 'modules' => Jetpack::get_translated_modules( $this->all_items ),
88 'i18n' => array(
89 'search_placeholder' => __( 'Search Modules…', 'jetpack' ),
90 ),
91 'modalinfo' => $this->module_info_check( $modal_info, $this->all_items ),
92 'nonces' => array(
93 'bulk' => wp_create_nonce( 'bulk-jetpack_page_jetpack_modules' ),
94 ),
95 )
96 );
97
98 wp_enqueue_script( 'jetpack-modules-list-table' );
99
100 /**
101 * Filters the js_templates callback value.
102 *
103 * @since 3.6.0
104 *
105 * @param array array( $this, 'js_templates' ) js_templates callback.
106 */
107 add_action( 'admin_footer', apply_filters( 'jetpack_modules_list_table_js_template_callback', array( $this, 'js_templates' ) ), 9 );
108 }
109
110 /**
111 * Output row template.
112 */
113 public function js_templates() {
114 ?>
115 <script type="text/html" id="tmpl-Jetpack_Modules_List_Table_Template">
116 <# var i = 0;
117 if ( data.items.length ) {
118 _.each( data.items, function( item, key, list ) {
119 if ( item === undefined ) return; #>
120 <tr class="jetpack-module <# if ( ++i % 2 ) { #> alternate<# } #><# if ( item.activated ) { #> active<# } #><# if ( ! item.available ) { #> unavailable<# } #>" id="{{{ item.module }}}">
121 <th scope="row" class="check-column">
122 <input type="checkbox" name="modules[]" value="{{{ item.module }}}" />
123 </th>
124 <td class='name column-name'>
125 <span class='info'><a href="{{{item.learn_more_button}}}" target="blank">{{{ item.name }}}</a></span>
126 <div class="row-actions">
127 <# if ( item.configurable ) { #>
128 <span class='configure'>{{{ item.configurable }}}</span>
129 <# } #>
130 <# if ( item.activated && 'vaultpress' !== item.module && item.available ) { #>
131 <span class='delete'><a href="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>?page=jetpack&#038;action=deactivate&#038;module={{{ item.module }}}&#038;_wpnonce={{{ item.deactivate_nonce }}}"><?php esc_html_e( 'Deactivate', 'jetpack' ); ?></a></span>
132 <# } else if ( item.available ) { #>
133 <span class='activate'><a href="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>?page=jetpack&#038;action=activate&#038;module={{{ item.module }}}&#038;_wpnonce={{{ item.activate_nonce }}}"><?php esc_html_e( 'Activate', 'jetpack' ); ?></a></span>
134 <# } #>
135 <# if ( ! item.available ) { #>
136 <span class='unavailable_reason'>{{{ item.unavailable_reason }}}</span>
137 <# } #>
138 </div>
139 </td>
140 </tr>
141 <#
142 });
143 } else {
144 #>
145 <tr class="no-modules-found">
146 <td colspan="2"><?php esc_html_e( 'No Modules Found', 'jetpack' ); ?></td>
147 </tr>
148 <#
149 }
150 #>
151 </script>
152 <?php
153 }
154
155 /**
156 * Get views data.
157 *
158 * @return array Maps identifier to display HTML.
159 */
160 public function get_views() {
161 /** This filter is already documented in class.jetpack-modules-list-table.php */
162 $modules = apply_filters( 'jetpack_modules_list_table_items', Jetpack_Admin::init()->get_modules() );
163 $array_of_module_tags = wp_list_pluck( $modules, 'module_tags' );
164 $module_tags = array_merge( ...array_values( $array_of_module_tags ) );
165 $module_tags = array_map( 'jetpack_get_module_i18n_tag', $module_tags );
166 $module_tags_unique = array_count_values( $module_tags );
167 ksort( $module_tags_unique );
168
169 $format = '<a href="%3$s"%4$s data-title="%1$s">%1$s <span class="count">(%2$s)</span></a>';
170 $title = __( 'All', 'jetpack' );
171 $count = count( $modules );
172 $url = esc_url( remove_query_arg( 'module_tag' ) );
173 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
174 $current = empty( $_GET['module_tag'] ) ? ' class="current all"' : ' class="all"';
175 $views = array(
176 'all' => sprintf( $format, $title, $count, $url, $current ),
177 );
178 foreach ( $module_tags_unique as $title => $count ) {
179 $key = sanitize_title( $title );
180 $display_title = esc_html( wptexturize( $title ) );
181 $url = esc_url( add_query_arg( 'module_tag', rawurlencode( $title ) ) );
182 $current = '';
183 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
184 if ( ! empty( $_GET['module_tag'] ) && $title === $_GET['module_tag'] ) {
185 $current = ' class="current"';
186 }
187 $views[ $key ] = sprintf( $format, $display_title, $count, $url, $current );
188 }
189 return $views;
190 }
191
192 /**
193 * Output views HTML.
194 */
195 public function views() {
196 $views = $this->get_views();
197
198 echo "<ul class='subsubsub'>\n";
199 foreach ( $views as $class => $view ) {
200 $views[ $class ] = "\t<li class='$class'>$view</li>";
201 }
202 echo implode( "\n", $views ) . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Is HTML. Escaping happens in get_views().
203 echo '</ul>';
204 }
205
206 /**
207 * Filter a modules array for displayed items.
208 *
209 * @param array $modules Modules.
210 * @return array Displayed modules.
211 */
212 public function filter_displayed_table_items( $modules ) {
213 return array_filter( $modules, array( $this, 'is_module_displayed' ) );
214 }
215
216 /**
217 * Determine if a module is displayed.
218 *
219 * @param array $module Module data.
220 * @return bool
221 */
222 public static function is_module_displayed( $module ) {
223 // Handle module tag based filtering.
224 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
225 if ( ! empty( $_REQUEST['module_tag'] ) ) {
226 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
227 $module_tag = sanitize_text_field( wp_unslash( $_REQUEST['module_tag'] ) );
228 if ( ! in_array( $module_tag, array_map( 'jetpack_get_module_i18n_tag', $module['module_tags'] ), true ) ) {
229 return false;
230 }
231 }
232
233 // If nothing rejected it, include it!
234 return true;
235 }
236
237 /**
238 * Sort callback to put modules with `requires_connection` last.
239 *
240 * @param array $module1 Module data.
241 * @param array $module2 Module data.
242 * @return int Indicating the relative ordering of module1 and module2.
243 */
244 public static function sort_requires_connection_last( $module1, $module2 ) {
245 if ( (bool) $module1['requires_connection'] === (bool) $module2['requires_connection'] ) {
246 return 0;
247 }
248 if ( $module1['requires_connection'] ) {
249 return 1;
250 }
251 if ( $module2['requires_connection'] ) {
252 return -1;
253 }
254
255 return 0;
256 }
257
258 /**
259 * Get table columns.
260 *
261 * @return string[] Column name to header HTML.
262 */
263 public function get_columns() {
264 $columns = array(
265 'cb' => '<input type="checkbox" />',
266 'name' => __( 'Name', 'jetpack' ),
267 );
268 return $columns;
269 }
270
271 /**
272 * Get bulk actions for the table.
273 *
274 * @return string[] Actions, code => text.
275 */
276 public function get_bulk_actions() {
277 $actions = array(
278 'bulk-activate' => __( 'Activate', 'jetpack' ),
279 'bulk-deactivate' => __( 'Deactivate', 'jetpack' ),
280 );
281 return $actions;
282 }
283
284 /**
285 * Print a single row of the table.
286 *
287 * @param object|array $item Item.
288 */
289 public function single_row( $item ) {
290 static $i = 0;
291 $row_class = ( ( ++$i ) % 2 ) ? ' alternate' : '';
292
293 if ( ! empty( $item['activated'] ) ) {
294 $row_class .= ' active';
295 }
296
297 if ( ! Jetpack_Admin::is_module_available( $item ) ) {
298 $row_class .= ' unavailable';
299 }
300
301 echo '<tr class="jetpack-module' . esc_attr( $row_class ) . '" id="' . esc_attr( $item['module'] ) . '">';
302 $this->single_row_columns( $item );
303 echo '</tr>';
304 }
305
306 /**
307 * Table classes.
308 *
309 * @return string[] HTML.
310 */
311 public function get_table_classes() {
312 return array( 'table', 'table-bordered', 'wp-list-table', 'widefat', 'fixed', 'jetpack-modules' );
313 }
314
315 /**
316 * Column checkbox.
317 *
318 * @param object|array $item Item.
319 * @return string HTML.
320 */
321 public function column_cb( $item ) {
322 if ( ! Jetpack_Admin::is_module_available( $item ) ) {
323 return '';
324 }
325
326 return sprintf( '<input type="checkbox" name="modules[]" value="%s" />', $item['module'] );
327 }
328
329 /**
330 * Column icon.
331 *
332 * @return string HTML.
333 */
334 public function column_icon() {
335 $badge_text = '';
336 $free_text = '';
337 ob_start();
338 ?>
339 <a href="#TB_inline?width=600&height=550&inlineId=more-info-module-settings-modal" class="thickbox">
340 <div class="module-image">
341 <p><span class="module-image-badge"><?php echo esc_html( $badge_text ); ?></span><span class="module-image-free" style="display: none"><?php echo esc_html( $free_text ); ?></span></p>
342 </div>
343 </a>
344 <?php
345 return ob_get_clean();
346 }
347
348 /**
349 * Column name.
350 *
351 * @param object|array $item Item.
352 * @return string HTML.
353 */
354 public function column_name( $item ) {
355 $actions = array(
356 'info' => sprintf( '<a href="%s" target="blank">%s</a>', esc_url( $item['learn_more_button'] ), esc_html__( 'Feature Info', 'jetpack' ) ),
357 );
358
359 if ( ! empty( $item['configurable'] ) ) {
360 $actions['configure'] = $item['configurable'];
361 }
362
363 if ( empty( $item['activated'] ) && Jetpack_Admin::is_module_available( $item ) ) {
364 $url = wp_nonce_url(
365 Jetpack::admin_url(
366 array(
367 'page' => 'jetpack',
368 'action' => 'activate',
369 'module' => $item['module'],
370 )
371 ),
372 'jetpack_activate-' . $item['module']
373 );
374 $actions['activate'] = sprintf( '<a href="%s">%s</a>', esc_url( $url ), esc_html__( 'Activate', 'jetpack' ) );
375 } elseif ( ! empty( $item['activated'] ) ) {
376 $url = wp_nonce_url(
377 Jetpack::admin_url(
378 array(
379 'page' => 'jetpack',
380 'action' => 'deactivate',
381 'module' => $item['module'],
382 )
383 ),
384 'jetpack_deactivate-' . $item['module']
385 );
386 $actions['delete'] = sprintf( '<a href="%s">%s</a>', esc_url( $url ), esc_html__( 'Deactivate', 'jetpack' ) );
387 }
388
389 return $this->row_actions( $actions ) . wptexturize( $item['name'] );
390 }
391
392 /**
393 * Column description.
394 *
395 * @param object|array $item Item.
396 * @return string HTML.
397 */
398 public function column_description( $item ) {
399 ob_start();
400 // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
401 /** This action is documented in class.jetpack-admin.php */
402 echo apply_filters( 'jetpack_short_module_description', $item['description'], $item['module'] );
403 /** This action is documented in class.jetpack-admin.php */
404 do_action( 'jetpack_learn_more_button_' . $item['module'] );
405 echo '<div id="more-info-' . $item['module'] . '" class="more-info">';
406 /** This action is documented in class.jetpack-admin.php */
407 do_action( 'jetpack_module_more_info_' . $item['module'] );
408 echo '</div>';
409 // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
410 return ob_get_clean();
411 }
412
413 /**
414 * Return module tags HTML.
415 *
416 * @param object|array $item Item.
417 * @return string HTML.
418 */
419 public function column_module_tags( $item ) {
420 $module_tags = array();
421 foreach ( array_map( 'jetpack_get_module_i18n_tag', $item['module_tags'] ) as $module_tag ) {
422 $module_tags[] = sprintf( '<a href="%3$s" data-title="%2$s">%1$s</a>', esc_html( $module_tag ), esc_attr( $module_tag ), esc_url( add_query_arg( 'module_tag', rawurlencode( $module_tag ) ) ) );
423 }
424 return implode( ', ', $module_tags );
425 }
426
427 /**
428 * Column default value.
429 *
430 * @param object|array $item Item.
431 * @param string $column_name Column name.
432 * @return string
433 */
434 public function column_default( $item, $column_name ) {
435 switch ( $column_name ) {
436 case 'icon':
437 case 'name':
438 case 'description':
439 return '';
440 default:
441 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
442 return print_r( $item, true );
443 }
444 }
445
446 /**
447 * Check if the info parameter provided in the URL corresponds to an actual module.
448 *
449 * @param string|false $info Info parameter.
450 * @param array $modules Modules array.
451 * @return string|false
452 */
453 public function module_info_check( $info, $modules ) {
454 if ( ! $info ) {
455 return false;
456 } elseif ( array_key_exists( $info, $modules ) ) {
457 return $info;
458 }
459 }
460
461 /**
462 * Core switched their `display_tablenav()` method to protected, so we can't access it directly.
463 * Instead, let's include an access function to make it doable without errors!
464 *
465 * @see https://github.com/WordPress/WordPress/commit/d28f6344de97616de8ece543ed290c4ba2383622
466 *
467 * @param string $which Which nav table to display.
468 * @return mixed
469 */
470 public function unprotected_display_tablenav( $which = 'top' ) {
471 return $this->display_tablenav( $which );
472 }
473
474 }
475