diff --git a/wp-admin/includes/class-wp-list-table.php b/wp-admin/includes/class-wp-list-table.php
index aa56a3e9cd..ee5f9f9b34 100644
--- a/wp-admin/includes/class-wp-list-table.php
+++ b/wp-admin/includes/class-wp-list-table.php
@@ -484,7 +484,7 @@ class WP_List_Table {
if ( empty( $this->_pagination_args ) )
return;
- extract( $this->_pagination_args );
+ extract( $this->_pagination_args, EXTR_SKIP );
$output = '' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '';
@@ -543,7 +543,10 @@ class WP_List_Table {
'»'
);
- $output .= "\n';
+ $pagination_links_class = 'pagination-links';
+ if ( ! empty( $infinite_scroll ) )
+ $pagination_links_class = ' hide-if-js';
+ $output .= "\n';
if ( $total_pages )
$page_class = $total_pages < 2 ? ' one-page' : '';
@@ -872,7 +875,7 @@ class WP_List_Table {
$this->prepare_items();
extract( $this->_args );
- extract( $this->_pagination_args );
+ extract( $this->_pagination_args, EXTR_SKIP );
ob_start();
if ( ! empty( $_REQUEST['no_placeholder'] ) )
diff --git a/wp-admin/includes/class-wp-theme-install-list-table.php b/wp-admin/includes/class-wp-theme-install-list-table.php
index eab12598a2..41fbb64506 100644
--- a/wp-admin/includes/class-wp-theme-install-list-table.php
+++ b/wp-admin/includes/class-wp-theme-install-list-table.php
@@ -7,25 +7,30 @@
* @since 3.1.0
* @access private
*/
-class WP_Theme_Install_List_Table extends WP_List_Table {
+class WP_Theme_Install_List_Table extends WP_Themes_List_Table {
- function __construct() {
- parent::__construct( array(
- 'ajax' => true,
- ) );
- }
+ var $features = array();
function ajax_user_can() {
- return current_user_can('install_themes');
+ return current_user_can( 'install_themes' );
}
function prepare_items() {
include( ABSPATH . 'wp-admin/includes/theme-install.php' );
- global $tabs, $tab, $paged, $type, $term, $theme_field_defaults;
-
+ global $tabs, $tab, $paged, $type, $theme_field_defaults;
wp_reset_vars( array( 'tab' ) );
+ $search_terms = array();
+ $search_string = '';
+ if ( ! empty( $_REQUEST['s'] ) ){
+ $search_string = strtolower( stripslashes( $_REQUEST['s'] ) );
+ $search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) );
+ }
+
+ if ( ! empty( $_REQUEST['features'] ) )
+ $this->features = $_REQUEST['features'];
+
$paged = $this->get_pagenum();
$per_page = 36;
@@ -55,29 +60,21 @@ class WP_Theme_Install_List_Table extends WP_List_Table {
switch ( $tab ) {
case 'search':
$type = isset( $_REQUEST['type'] ) ? stripslashes( $_REQUEST['type'] ) : '';
- $term = isset( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '';
-
switch ( $type ) {
case 'tag':
- $terms = explode( ',', $term );
- $terms = array_map( 'trim', $terms );
- $terms = array_map( 'sanitize_title_with_dashes', $terms );
- $args['tag'] = $terms;
+ $args['tag'] = array_map( 'sanitize_title_with_dashes', $search_terms );
break;
case 'term':
- $args['search'] = $term;
+ $args['search'] = $search_string;
break;
case 'author':
- $args['author'] = $term;
+ $args['author'] = $search_string;
break;
}
- if ( !empty( $_REQUEST['features'] ) ) {
- $terms = $_REQUEST['features'];
- $terms = array_map( 'trim', $terms );
- $terms = array_map( 'sanitize_title_with_dashes', $terms );
- $args['tag'] = $terms;
- $_REQUEST['s'] = implode( ',', $terms );
+ if ( ! empty( $this->features ) ) {
+ $args['tag'] = $this->features;
+ $_REQUEST['s'] = implode( ',', $this->features );
$_REQUEST['type'] = 'tag';
}
@@ -95,7 +92,7 @@ class WP_Theme_Install_List_Table extends WP_List_Table {
$args = false;
}
- if ( !$args )
+ if ( ! $args )
return;
$api = themes_api( 'query_themes', $args );
@@ -108,6 +105,7 @@ class WP_Theme_Install_List_Table extends WP_List_Table {
$this->set_pagination_args( array(
'total_items' => $api->info['results'],
'per_page' => $per_page,
+ 'infinite_scroll' => true,
) );
}
@@ -128,12 +126,7 @@ class WP_Theme_Install_List_Table extends WP_List_Table {
return $display_tabs;
}
- function get_columns() {
- return array();
- }
-
function display() {
-
wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
?>
@@ -149,12 +142,8 @@ class WP_Theme_Install_List_Table extends WP_List_Table {
display_rows_or_placeholder(); ?>
-
- pagination( 'bottom' ); ?>
-
-
-
-
Install screen
+ * @uses $type Global; type of search.
+ */
+ function _js_vars() {
+ global $tab, $type;
+ parent::_js_vars( compact( $tab, $type ) );
+ }
}
diff --git a/wp-admin/includes/class-wp-themes-list-table.php b/wp-admin/includes/class-wp-themes-list-table.php
index 257ce1f6c9..e1ce61caa4 100644
--- a/wp-admin/includes/class-wp-themes-list-table.php
+++ b/wp-admin/includes/class-wp-themes-list-table.php
@@ -20,7 +20,7 @@ class WP_Themes_List_Table extends WP_List_Table {
function ajax_user_can() {
// Do not check edit_theme_options here. AJAX calls for available themes require switch_themes.
- return current_user_can('switch_themes');
+ return current_user_can( 'switch_themes' );
}
function prepare_items() {
@@ -52,6 +52,7 @@ class WP_Themes_List_Table extends WP_List_Table {
$this->set_pagination_args( array(
'total_items' => count( $themes ),
'per_page' => $per_page,
+ 'infinite_scroll' => true,
) );
}
@@ -202,4 +203,35 @@ class WP_Themes_List_Table extends WP_List_Table {
return true;
}
+
+ /**
+ * Send required variables to JavaScript land
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @uses $this->features Array of all feature search terms.
+ * @uses get_pagenum()
+ * @uses _pagination_args['total_pages']
+ */
+ function _js_vars( $extra_args = array() ) {
+ $search_string = isset( $_REQUEST['s'] ) ? esc_attr( stripslashes( $_REQUEST['s'] ) ) : '';
+
+ $total_pages = 1;
+ if ( ! empty( $this->_pagination_args['total_pages'] ) )
+ $total_pages = $this->_pagination_args['total_pages'];
+
+ $args = array(
+ 'search' => $search_string,
+ 'features' => $this->features,
+ 'paged' => $this->get_pagenum(),
+ 'total_pages' => $total_pages,
+ );
+
+ if ( is_array( $extra_args ) )
+ $args = array_merge( $args, $extra_args );
+
+ printf( "\n", json_encode( $args ) );
+ parent::_js_vars();
+ }
}
diff --git a/wp-admin/includes/list-table.php b/wp-admin/includes/list-table.php
index f9785d7ac6..2dff578e0d 100644
--- a/wp-admin/includes/list-table.php
+++ b/wp-admin/includes/list-table.php
@@ -28,7 +28,7 @@ function _get_list_table( $class ) {
'WP_Links_List_Table' => 'links',
'WP_Plugin_Install_List_Table' => 'plugin-install',
'WP_Themes_List_Table' => 'themes',
- 'WP_Theme_Install_List_Table' => 'theme-install',
+ 'WP_Theme_Install_List_Table' => array( 'themes', 'theme-install' ),
'WP_Plugins_List_Table' => 'plugins',
// Network Admin
'WP_MS_Sites_List_Table' => 'ms-sites',
@@ -37,7 +37,8 @@ function _get_list_table( $class ) {
);
if ( isset( $core_classes[ $class ] ) ) {
- require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $core_classes[ $class ] . '-list-table.php' );
+ foreach ( (array) $core_classes[ $class ] as $required )
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $required . '-list-table.php' );
return new $class;
}
diff --git a/wp-admin/js/theme.dev.js b/wp-admin/js/theme.dev.js
index 98b44583a7..54788433cb 100644
--- a/wp-admin/js/theme.dev.js
+++ b/wp-admin/js/theme.dev.js
@@ -54,48 +54,50 @@ jQuery( document ).ready( function($) {
theme_viewer.init();
});
-var ThemeScroller;
+/**
+ * Class that provides infinite scroll for Themes admin screens
+ *
+ * @since 3.4
+ *
+ * @uses ajaxurl
+ * @uses list_args
+ * @uses theme_list_args
+ * @uses $('#_ajax_fetch_list_nonce').val()
+* */
+var ThemeScroller;
(function($){
ThemeScroller = {
- // Inputs
nonce: '',
- search: '',
- tab: '',
- type: '',
- nextPage: 2,
- features: {},
-
- // Preferences
+ nextPage: 2, // By default, assume we're on the first page.
+ querying: false,
scrollPollingDelay: 500,
failedRetryDelay: 4000,
outListBottomThreshold: 300,
- // Flags
- scrolling: false,
- querying: false,
-
+ /**
+ * Initializer
+ *
+ * @since 3.4
+ * @access private
+ */
init: function() {
var self = this,
- startPage,
- queryArray = {},
- queryString = window.location.search;
+ startPage;
- // We're using infinite scrolling, so hide all pagination.
- $('.pagination-links').hide();
-
- // Parse GET query string
- queryArray = this.parseQuery( queryString.substring( 1 ) );
+ // Get out early if we don't have the required arguments.
+ if ( typeof ajaxurl === 'undefined' ||
+ typeof list_args === 'undefined' ||
+ typeof theme_list_args === 'undefined' ) {
+ $('.pagination-links').show();
+ return;
+ }
// Handle inputs
this.nonce = $('#_ajax_fetch_list_nonce').val();
- this.search = queryArray['s'];
- this.features = queryArray['features'];
- this.tab = queryArray['tab'];
- this.type = queryArray['type'];
- startPage = parseInt( queryArray['paged'], 10 );
- if ( ! isNaN( startPage ) )
+ startPage = theme_list_args.paged;
+ if ( startPage !== undefined )
this.nextPage = ( startPage + 1 );
// Cache jQuery selectors
@@ -104,12 +106,25 @@ var ThemeScroller;
this.$window = $(window);
this.$document = $(document);
- if ( $('.tablenav-pages').length )
+ /**
+ * If there are more pages to query, then start polling to track
+ * when user hits the bottom of the current page
+ */
+ if ( theme_list_args.total_pages !== undefined &&
+ theme_list_args.total_pages >= this.nextPage )
this.pollInterval =
setInterval( function() {
return self.poll();
}, this.scrollPollingDelay );
},
+
+ /**
+ * Checks to see if user has scrolled to bottom of page.
+ * If so, requests another page of content from self.ajax().
+ *
+ * @since 3.4
+ * @access private
+ */
poll: function() {
var bottom = this.$document.scrollTop() + this.$window.innerHeight();
@@ -119,32 +134,49 @@ var ThemeScroller;
this.ajax();
},
+
+ /**
+ * Applies results passed from this.ajax() to $outList
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @param results Array with results from this.ajax() query.
+ */
process: function( results ) {
if ( ( results === undefined ) ||
- ( results.rows.indexOf( 'no-items' ) != -1 ) ) {
+ ( results.rows === undefined ) ||
+ ( results.rows.indexOf( 'no-items' ) != -1 ) ) {
clearInterval( this.pollInterval );
return;
}
- var totalPages = parseInt( results.total_pages, 10 );
- if ( this.nextPage > totalPages )
+ if ( this.nextPage > theme_list_args.total_pages )
clearInterval( this.pollInterval );
- if ( this.nextPage <= ( totalPages + 1 ) )
+ if ( this.nextPage <= ( theme_list_args.total_pages + 1 ) )
this.$outList.append( results.rows );
},
+
+ /**
+ * Queries next page of themes
+ *
+ * @since 3.4
+ * @access private
+ */
ajax: function() {
var self = this;
+
this.querying = true;
var query = {
action: 'fetch-list',
- tab: this.tab,
paged: this.nextPage,
- s: this.search,
- type: this.type,
+ s: theme_list_args.search,
+ tab: theme_list_args.tab,
+ type: theme_list_args.type,
_ajax_fetch_list_nonce: this.nonce,
- 'features[]': this.features,
+ 'features[]': theme_list_args.features,
'list_args': list_args
};
@@ -159,40 +191,13 @@ var ThemeScroller;
.fail( function() {
self.$spinner.css( 'visibility', 'hidden' );
self.querying = false;
- setTimeout( function() { self.ajax(); }, self.failedRetryDelay )
+ setTimeout( function() { self.ajax(); }, self.failedRetryDelay );
});
- },
- parseQuery: function( query ) {
- var params = {};
- if ( ! query )
- return params;
-
- var pairs = query.split( /[;&]/ );
- for ( var i = 0; i < pairs.length; i++ ) {
- var keyVal = pairs[i].split( '=' );
-
- if ( ! keyVal || keyVal.length != 2 )
- continue;
-
- var key = unescape( keyVal[0] );
- var val = unescape( keyVal[1] );
- val = val.replace( /\+/g, ' ' );
- key = key.replace( /\[.*\]$/g, '' );
-
- if ( params[key] === undefined ) {
- params[key] = val;
- } else {
- var oldVal = params[key];
- if ( ! $.isArray( params[key] ) )
- params[key] = new Array( oldVal, val );
- else
- params[key].push( val );
- }
- }
- return params;
}
}
- $(document).ready( function( $ ) { ThemeScroller.init(); });
+ $(document).ready( function($) {
+ ThemeScroller.init();
+ });
})(jQuery);