2022-04-02 10:26:41 +02:00
< ? php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
* Jetpack modules list table .
*
* @ package automattic / jetpack
*/
2019-11-15 23:26:29 +01:00
use Automattic\Jetpack\Assets ;
if ( ! class_exists ( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ;
}
2022-04-02 10:26:41 +02:00
/**
* Jetpack modules list table .
*/
2019-11-15 23:26:29 +01:00
class Jetpack_Modules_List_Table extends WP_List_Table {
2022-04-02 10:26:41 +02:00
/** Constructor. */
public function __construct () {
2019-11-15 23:26:29 +01:00
parent :: __construct ();
Jetpack :: init ();
if ( $this -> compat_fields && is_array ( $this -> compat_fields ) ) {
array_push ( $this -> compat_fields , 'all_items' );
}
/**
* Filters the list of modules available to be displayed in the Jetpack Settings screen .
*
* @ since 3.0 . 0
*
2020-10-20 18:05:12 +02:00
* @ param array $modules Array of Jetpack modules .
2019-11-15 23:26:29 +01:00
*/
2020-10-20 18:05:12 +02:00
$this -> all_items = apply_filters ( 'jetpack_modules_list_table_items' , Jetpack_Admin :: init () -> get_modules () );
$this -> items = $this -> all_items ;
$this -> items = $this -> filter_displayed_table_items ( $this -> items );
2019-11-15 23:26:29 +01:00
$this -> _column_headers = array ( $this -> get_columns (), array (), array (), 'name' );
2022-06-16 14:01:47 +02:00
// 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()`.
$modal_info = isset ( $_GET [ 'info' ] ) ? wp_unslash ( $_GET [ 'info' ] ) : false ;
2019-11-15 23:26:29 +01:00
2022-12-15 17:41:53 +01:00
// Adding in a hidden h1 heading for screen-readers.
?>
< h1 class = " screen-reader-text " >< ? php esc_html_e ( 'Jetpack Modules List' , 'jetpack' ); ?> </h1>
< ? php
2019-11-15 23:26:29 +01:00
wp_register_script (
'models.jetpack-modules' ,
Assets :: get_file_url_for_environment (
'_inc/build/jetpack-modules.models.min.js' ,
'_inc/jetpack-modules.models.js'
),
2023-04-26 17:39:43 +02:00
array ( 'jquery' , 'backbone' , 'underscore' ),
2022-04-02 10:26:41 +02:00
JETPACK__VERSION ,
false // @todo Can this be put in the footer?
2019-11-15 23:26:29 +01:00
);
wp_register_script (
'views.jetpack-modules' ,
Assets :: get_file_url_for_environment (
'_inc/build/jetpack-modules.views.min.js' ,
'_inc/jetpack-modules.views.js'
),
2023-04-26 17:39:43 +02:00
array ( 'jquery' , 'backbone' , 'underscore' , 'wp-util' ),
2022-04-02 10:26:41 +02:00
JETPACK__VERSION ,
false // @todo Can this be put in the footer?
2019-11-15 23:26:29 +01:00
);
wp_register_script (
'jetpack-modules-list-table' ,
Assets :: get_file_url_for_environment (
'_inc/build/jetpack-modules.min.js' ,
'_inc/jetpack-modules.js'
),
array (
'views.jetpack-modules' ,
'models.jetpack-modules' ,
'jquery' ,
),
JETPACK__VERSION ,
true
);
wp_localize_script (
'jetpack-modules-list-table' ,
'jetpackModulesData' ,
array (
'modules' => Jetpack :: get_translated_modules ( $this -> all_items ),
'i18n' => array (
'search_placeholder' => __ ( 'Search Modules…' , 'jetpack' ),
),
'modalinfo' => $this -> module_info_check ( $modal_info , $this -> all_items ),
'nonces' => array (
'bulk' => wp_create_nonce ( 'bulk-jetpack_page_jetpack_modules' ),
),
)
);
wp_enqueue_script ( 'jetpack-modules-list-table' );
/**
* Filters the js_templates callback value .
*
* @ since 3.6 . 0
*
* @ param array array ( $this , 'js_templates' ) js_templates callback .
*/
add_action ( 'admin_footer' , apply_filters ( 'jetpack_modules_list_table_js_template_callback' , array ( $this , 'js_templates' ) ), 9 );
}
2022-04-02 10:26:41 +02:00
/**
* Output row template .
*/
public function js_templates () {
2019-11-15 23:26:29 +01:00
?>
< script type = " text/html " id = " tmpl-Jetpack_Modules_List_Table_Template " >
< # var i = 0;
if ( data . items . length ) {
_ . each ( data . items , function ( item , key , list ) {
2020-03-03 18:49:45 +01:00
if ( item === undefined ) return ; #>
2019-11-15 23:26:29 +01:00
< tr class = " jetpack-module <# if ( ++i % 2 ) { #> alternate<# } #><# if ( item.activated ) { #> active<# } #><# if ( ! item.available ) { #> unavailable<# } #> " id = " { { { item.module }}} " >
< th scope = " row " class = " check-column " >
< input type = " checkbox " name = " modules[] " value = " { { { item.module }}} " />
</ th >
< td class = 'name column-name' >
< span class = 'info' >< a href = " { { { item.learn_more_button}}} " target = " blank " > {{{ item . name }}} </ a ></ span >
< div class = " row-actions " >
< # if ( item.configurable ) { #>
< span class = 'configure' > {{{ item . configurable }}} </ span >
< # } #>
2022-04-02 10:26:41 +02:00
< # if ( item.activated && 'vaultpress' !== item.module && item.available ) { #>
< span class = 'delete' >< a href = " <?php echo esc_url( admin_url( 'admin.php' ) ); ?>?page=jetpack&action=deactivate&module= { { { item.module }}}&_wpnonce= { { { item.deactivate_nonce }}} " >< ? php esc_html_e ( 'Deactivate' , 'jetpack' ); ?> </a></span>
< # } else if ( item.available ) { #>
< span class = 'activate' >< a href = " <?php echo esc_url( admin_url( 'admin.php' ) ); ?>?page=jetpack&action=activate&module= { { { item.module }}}&_wpnonce= { { { item.activate_nonce }}} " >< ? php esc_html_e ( 'Activate' , 'jetpack' ); ?> </a></span>
2019-11-15 23:26:29 +01:00
< # } #>
2021-07-23 11:58:50 +02:00
< # if ( ! item.available ) { #>
< span class = 'unavailable_reason' > {{{ item . unavailable_reason }}} </ span >
< # } #>
2019-11-15 23:26:29 +01:00
</ div >
</ td >
</ tr >
< #
});
} else {
#>
< tr class = " no-modules-found " >
< td colspan = " 2 " >< ? php esc_html_e ( 'No Modules Found' , 'jetpack' ); ?> </td>
</ tr >
< #
}
#>
</ script >
< ? php
}
2022-04-02 10:26:41 +02:00
/**
* Get views data .
*
* @ return array Maps identifier to display HTML .
*/
public function get_views () {
2020-10-20 18:05:12 +02:00
/** This filter is already documented in class.jetpack-modules-list-table.php */
$modules = apply_filters ( 'jetpack_modules_list_table_items' , Jetpack_Admin :: init () -> get_modules () );
2019-11-15 23:26:29 +01:00
$array_of_module_tags = wp_list_pluck ( $modules , 'module_tags' );
2021-04-27 08:32:47 +02:00
$module_tags = array_merge ( ... array_values ( $array_of_module_tags ) );
2019-11-15 23:26:29 +01:00
$module_tags_unique = array_count_values ( $module_tags );
ksort ( $module_tags_unique );
2022-04-02 10:26:41 +02:00
$format = '<a href="%3$s"%4$s data-title="%1$s">%1$s <span class="count">(%2$s)</span></a>' ;
$title = __ ( 'All' , 'jetpack' );
$count = count ( $modules );
$url = esc_url ( remove_query_arg ( 'module_tag' ) );
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
2019-11-15 23:26:29 +01:00
$current = empty ( $_GET [ 'module_tag' ] ) ? ' class="current all"' : ' class="all"' ;
$views = array (
'all' => sprintf ( $format , $title , $count , $url , $current ),
);
foreach ( $module_tags_unique as $title => $count ) {
$key = sanitize_title ( $title );
$display_title = esc_html ( wptexturize ( $title ) );
2022-04-02 10:26:41 +02:00
$url = esc_url ( add_query_arg ( 'module_tag' , rawurlencode ( $title ) ) );
2019-11-15 23:26:29 +01:00
$current = '' ;
2022-04-02 10:26:41 +02:00
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
if ( ! empty ( $_GET [ 'module_tag' ] ) && $title === $_GET [ 'module_tag' ] ) {
2019-11-15 23:26:29 +01:00
$current = ' class="current"' ;
}
$views [ $key ] = sprintf ( $format , $display_title , $count , $url , $current );
}
return $views ;
}
2022-04-02 10:26:41 +02:00
/**
* Output views HTML .
*/
public function views () {
2019-11-15 23:26:29 +01:00
$views = $this -> get_views ();
echo " <ul class='subsubsub'> \n " ;
foreach ( $views as $class => $view ) {
$views [ $class ] = " \t <li class=' $class '> $view </li> " ;
}
2022-04-02 10:26:41 +02:00
echo implode ( " \n " , $views ) . " \n " ; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Is HTML. Escaping happens in get_views().
2019-11-15 23:26:29 +01:00
echo '</ul>' ;
}
2022-04-02 10:26:41 +02:00
/**
* Filter a modules array for displayed items .
*
* @ param array $modules Modules .
* @ return array Displayed modules .
*/
public function filter_displayed_table_items ( $modules ) {
2019-11-15 23:26:29 +01:00
return array_filter ( $modules , array ( $this , 'is_module_displayed' ) );
}
2022-04-02 10:26:41 +02:00
/**
* Determine if a module is displayed .
*
* @ param array $module Module data .
* @ return bool
*/
public static function is_module_displayed ( $module ) {
2019-11-15 23:26:29 +01:00
// Handle module tag based filtering.
2022-04-02 10:26:41 +02:00
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
2019-11-15 23:26:29 +01:00
if ( ! empty ( $_REQUEST [ 'module_tag' ] ) ) {
2022-04-02 10:26:41 +02:00
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a view, not a model or controller.
2022-06-16 14:01:47 +02:00
$module_tag = sanitize_text_field ( wp_unslash ( $_REQUEST [ 'module_tag' ] ) );
2022-04-02 10:26:41 +02:00
if ( ! in_array ( $module_tag , $module [ 'module_tags' ], true ) ) {
2019-11-15 23:26:29 +01:00
return false ;
}
}
// If nothing rejected it, include it!
return true ;
}
2022-04-02 10:26:41 +02:00
/**
* Sort callback to put modules with `requires_connection` last .
*
* @ param array $module1 Module data .
* @ param array $module2 Module data .
* @ return int Indicating the relative ordering of module1 and module2 .
*/
public static function sort_requires_connection_last ( $module1 , $module2 ) {
if ( ( bool ) $module1 [ 'requires_connection' ] === ( bool ) $module2 [ 'requires_connection' ] ) {
2019-11-15 23:26:29 +01:00
return 0 ;
}
if ( $module1 [ 'requires_connection' ] ) {
return 1 ;
}
if ( $module2 [ 'requires_connection' ] ) {
return - 1 ;
}
return 0 ;
}
2022-04-02 10:26:41 +02:00
/**
* Get table columns .
*
* @ return string [] Column name to header HTML .
*/
public function get_columns () {
2019-11-15 23:26:29 +01:00
$columns = array (
'cb' => '<input type="checkbox" />' ,
'name' => __ ( 'Name' , 'jetpack' ),
);
return $columns ;
}
2022-04-02 10:26:41 +02:00
/**
* Get bulk actions for the table .
*
* @ return string [] Actions , code => text .
*/
public function get_bulk_actions () {
2019-11-15 23:26:29 +01:00
$actions = array (
'bulk-activate' => __ ( 'Activate' , 'jetpack' ),
'bulk-deactivate' => __ ( 'Deactivate' , 'jetpack' ),
);
return $actions ;
}
2022-04-02 10:26:41 +02:00
/**
* Print a single row of the table .
*
* @ param object | array $item Item .
*/
public function single_row ( $item ) {
2019-11-15 23:26:29 +01:00
static $i = 0 ;
2022-04-02 10:26:41 +02:00
$row_class = ( ( ++ $i ) % 2 ) ? ' alternate' : '' ;
2019-11-15 23:26:29 +01:00
if ( ! empty ( $item [ 'activated' ] ) ) {
$row_class .= ' active' ;
}
if ( ! Jetpack_Admin :: is_module_available ( $item ) ) {
$row_class .= ' unavailable' ;
}
echo '<tr class="jetpack-module' . esc_attr ( $row_class ) . '" id="' . esc_attr ( $item [ 'module' ] ) . '">' ;
$this -> single_row_columns ( $item );
echo '</tr>' ;
}
2022-04-02 10:26:41 +02:00
/**
* Table classes .
*
* @ return string [] HTML .
*/
public function get_table_classes () {
2019-11-15 23:26:29 +01:00
return array ( 'table' , 'table-bordered' , 'wp-list-table' , 'widefat' , 'fixed' , 'jetpack-modules' );
}
2022-04-02 10:26:41 +02:00
/**
* Column checkbox .
*
* @ param object | array $item Item .
* @ return string HTML .
*/
public function column_cb ( $item ) {
2019-11-15 23:26:29 +01:00
if ( ! Jetpack_Admin :: is_module_available ( $item ) ) {
return '' ;
}
return sprintf ( '<input type="checkbox" name="modules[]" value="%s" />' , $item [ 'module' ] );
}
2022-04-02 10:26:41 +02:00
/**
* Column icon .
*
* @ return string HTML .
*/
public function column_icon () {
$badge_text = '' ;
$free_text = '' ;
2019-11-15 23:26:29 +01:00
ob_start ();
?>
< a href = " #TB_inline?width=600&height=550&inlineId=more-info-module-settings-modal " class = " thickbox " >
< div class = " module-image " >
2022-04-02 10:26:41 +02:00
< 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>
2019-11-15 23:26:29 +01:00
</ div >
</ a >
< ? php
return ob_get_clean ();
}
2022-04-02 10:26:41 +02:00
/**
* Column name .
*
* @ param object | array $item Item .
* @ return string HTML .
*/
public function column_name ( $item ) {
2019-11-15 23:26:29 +01:00
$actions = array (
'info' => sprintf ( '<a href="%s" target="blank">%s</a>' , esc_url ( $item [ 'learn_more_button' ] ), esc_html__ ( 'Feature Info' , 'jetpack' ) ),
);
if ( ! empty ( $item [ 'configurable' ] ) ) {
$actions [ 'configure' ] = $item [ 'configurable' ];
}
if ( empty ( $item [ 'activated' ] ) && Jetpack_Admin :: is_module_available ( $item ) ) {
$url = wp_nonce_url (
Jetpack :: admin_url (
array (
'page' => 'jetpack' ,
'action' => 'activate' ,
'module' => $item [ 'module' ],
)
),
'jetpack_activate-' . $item [ 'module' ]
);
$actions [ 'activate' ] = sprintf ( '<a href="%s">%s</a>' , esc_url ( $url ), esc_html__ ( 'Activate' , 'jetpack' ) );
} elseif ( ! empty ( $item [ 'activated' ] ) ) {
$url = wp_nonce_url (
Jetpack :: admin_url (
array (
'page' => 'jetpack' ,
'action' => 'deactivate' ,
'module' => $item [ 'module' ],
)
),
'jetpack_deactivate-' . $item [ 'module' ]
);
$actions [ 'delete' ] = sprintf ( '<a href="%s">%s</a>' , esc_url ( $url ), esc_html__ ( 'Deactivate' , 'jetpack' ) );
}
return $this -> row_actions ( $actions ) . wptexturize ( $item [ 'name' ] );
}
2022-04-02 10:26:41 +02:00
/**
* Column description .
*
* @ param object | array $item Item .
* @ return string HTML .
*/
public function column_description ( $item ) {
2019-11-15 23:26:29 +01:00
ob_start ();
2022-04-02 10:26:41 +02:00
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
2019-11-15 23:26:29 +01:00
/** This action is documented in class.jetpack-admin.php */
echo apply_filters ( 'jetpack_short_module_description' , $item [ 'description' ], $item [ 'module' ] );
/** This action is documented in class.jetpack-admin.php */
do_action ( 'jetpack_learn_more_button_' . $item [ 'module' ] );
echo '<div id="more-info-' . $item [ 'module' ] . '" class="more-info">' ;
/** This action is documented in class.jetpack-admin.php */
do_action ( 'jetpack_module_more_info_' . $item [ 'module' ] );
echo '</div>' ;
2022-04-02 10:26:41 +02:00
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
2019-11-15 23:26:29 +01:00
return ob_get_clean ();
}
2022-04-02 10:26:41 +02:00
/**
* Return module tags HTML .
*
* @ param object | array $item Item .
* @ return string HTML .
*/
public function column_module_tags ( $item ) {
2019-11-15 23:26:29 +01:00
$module_tags = array ();
foreach ( $item [ 'module_tags' ] as $module_tag ) {
2022-04-02 10:26:41 +02:00
$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 ) ) ) );
2019-11-15 23:26:29 +01:00
}
return implode ( ', ' , $module_tags );
}
2022-04-02 10:26:41 +02:00
/**
* Column default value .
*
* @ param object | array $item Item .
* @ param string $column_name Column name .
* @ return string
*/
public function column_default ( $item , $column_name ) {
2019-11-15 23:26:29 +01:00
switch ( $column_name ) {
case 'icon' :
case 'name' :
case 'description' :
2022-04-02 10:26:41 +02:00
return '' ;
2019-11-15 23:26:29 +01:00
default :
2022-04-02 10:26:41 +02:00
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
2019-11-15 23:26:29 +01:00
return print_r ( $item , true );
}
}
2022-04-02 10:26:41 +02:00
/**
* Check if the info parameter provided in the URL corresponds to an actual module .
*
* @ param string | false $info Info parameter .
* @ param array $modules Modules array .
* @ return string | false
*/
public function module_info_check ( $info , $modules ) {
if ( ! $info ) {
2019-11-15 23:26:29 +01:00
return false ;
} elseif ( array_key_exists ( $info , $modules ) ) {
return $info ;
}
}
/**
* Core switched their `display_tablenav()` method to protected , so we can ' t access it directly .
* Instead , let ' s include an access function to make it doable without errors !
*
* @ see https :// github . com / WordPress / WordPress / commit / d28f6344de97616de8ece543ed290c4ba2383622
*
2022-04-02 10:26:41 +02:00
* @ param string $which Which nav table to display .
2019-11-15 23:26:29 +01:00
* @ return mixed
*/
2022-04-02 10:26:41 +02:00
public function unprotected_display_tablenav ( $which = 'top' ) {
2019-11-15 23:26:29 +01:00
return $this -> display_tablenav ( $which );
}
}