Index: wp-admin/includes/theme.php
===================================================================
--- wp-admin/includes/theme.php (revision 27274)
+++ wp-admin/includes/theme.php (working copy)
@@ -452,4 +452,37 @@
*/
$prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes );
return array_values( $prepared_themes );
+}
+
+
+/**
+ * Get public themes from the themes directory
+ * and prepare them for JavaScript
+ *
+ * @since 3.8.0
+ *
+ * @uses themes_api themes_directory_sections
+ * @return array with $theme objects
+ */
+function prepare_public_themes_for_js( $themes = array() ) {
+
+ $sections = array(
+ 'featured' => __( 'Featured Themes' ),
+ 'popular' => __( 'Popular Themes' ),
+ 'new' => __( 'Newest Themes' ),
+ );
+
+ $sections = array_keys( $sections );
+
+ $args = array(
+ 'page' => 1,
+ 'per_page' => 12,
+ );
+
+ foreach ( $sections as $section ) {
+ $args['browse'] = $section;
+ $themes[ $section ] = themes_api( 'query_themes', $args );
+ }
+
+ return $themes;
}
\ No newline at end of file
Index: wp-admin/update.php
===================================================================
--- wp-admin/update.php (revision 27274)
+++ wp-admin/update.php (working copy)
@@ -199,7 +199,7 @@
include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api..
- check_admin_referer('install-theme_' . $theme);
+ check_admin_referer( 'install-theme' );
$api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
if ( is_wp_error($api) )
Index: wp-admin/js/theme.js
===================================================================
--- wp-admin/js/theme.js (revision 27274)
+++ wp-admin/js/theme.js (working copy)
@@ -12,8 +12,11 @@
themes.data = _wpThemeSettings;
l10n = themes.data.l10n;
+// Shortcut for (bool) isBrowsing check
+themes.isInstall = themes.data.settings.isBrowsing;
+
// Setup app structure
-_.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template });
+_.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template, orgAPI: {} });
themes.model = Backbone.Model.extend({});
@@ -55,6 +58,9 @@
this.$el.append( ' ' );
},
+ // Defines search element container
+ searchContainer: $( '#wpbody h2:first' ),
+
// Search input and view
// for current theme collection
search: function() {
@@ -66,11 +72,14 @@
return;
}
- view = new themes.view.Search({ collection: self.collection, parent: this });
+ view = new themes.view.Search({
+ collection: self.collection,
+ parent: this
+ });
// Render and append after screen title
view.render();
- $('#wpbody h2:first')
+ this.searchContainer
.append( $.parseHTML( '' + l10n.search + ' ' ) )
.append( view.el );
},
@@ -804,9 +813,330 @@
self.view.trigger( 'theme:close' );
self.themes.doSearch( query );
});
+
+ this.extraRoutes();
+ },
+
+ extraRoutes: function() {
+ return false;
}
};
+// --------------------
+// PUBLIC THEME BROWSER
+// --------------------
+//
+// The public theme browser relies on the basic structure of the script
+// but overwrites some aspects of the main views
+//
+// The theme collection is the same but models have different attributes
+// as determined by the public themes_api
+//
+// @ bool check if it's the 'browsing themes' screen
+if ( themes.isInstall ) {
+
+ // Extend the main view controller
+ // @see themes.view.Appearance {}
+ //
+ // Overwrites properties and functions as needed
+ _.extend( themes.view.Appearance.prototype, {
+
+ el: '#wpbody-content .wrap',
+
+ // Register events for sorting and filters in theme-navigation
+ events: {
+ 'click .theme-section': 'setSort',
+ 'click .theme-filter': 'setFilter',
+ 'click .more-filters': 'moreFilters'
+ },
+
+ // Handles all the rendering of the public theme directory
+ install: function( section ) {
+ // Create a new collection with the proper theme data
+ // for each section
+ this.collection = new themes.Collection( themes.data.browse.publicThemes[ section ].themes );
+
+ // Set ups the view and passes the section argument
+ this.view = new themes.view.Themes({
+ collection: this.collection,
+ section: section,
+ parent: this
+ });
+
+ // Reset pagination every time the install view handler is run
+ this.page = 0;
+
+ // Render and append
+ this.$el.find( '.themes' ).remove();
+ this.view.render();
+ this.$el.find( '.theme-browser' ).append( this.view.el );
+
+ this.uploader();
+ },
+
+ // Initial render method
+ render: function() {
+ this.search();
+ return this.install( this.options.section );
+ },
+
+ // Sorting navigation
+ setSort: function( event ) {
+ var $el = $( event.target ),
+ sort = $el.data( 'sort' );
+
+ // Bail if this is already active
+ if ( $el.hasClass( this.activeClass ) ) {
+ return;
+ }
+
+ $( '#theme-search-input' ).val( '' );
+
+ $( '.theme-section, .theme-filter' ).removeClass( this.activeClass );
+ $el.addClass( this.activeClass );
+
+ this.install( sort );
+
+ // Trigger a router.naviagte update
+ themes.router.navigate( themes.router.baseUrl( '?sort=' + sort ), { replace: true } );
+ },
+
+ // Filters and Tags
+ setFilter: function( event ) {
+ var $el = $( event.target ),
+ filter = $el.data( 'filter' ),
+ self = this,
+ data;
+
+ // Bail if this is already active
+ if ( $el.hasClass( this.activeClass ) ) {
+ return;
+ }
+
+ $( '.theme-filter, .theme-section' ).removeClass( this.activeClass );
+ $el.addClass( this.activeClass );
+
+ if ( ! filter ) {
+ return;
+ }
+
+ // Construct the filter request
+ // using the default values
+ data = _.defaults( {}, themes.orgAPI.data );
+
+ data.request = _.defaults({
+ tag: [ filter ]
+ }, themes.orgAPI.data.request );
+
+ // Send Ajax POST request to api.wordpress.org/themes
+ $.ajax({
+ url: themes.orgAPI.url,
+
+ // We want JSON data
+ dataType: 'json',
+ type: 'POST',
+
+ // Request data
+ data: data,
+
+ beforeSend: function() {
+ // Spin it
+ $( 'body' ).addClass( 'loading-themes' );
+ }
+ })
+ .done( function( data ) {
+ console.log(data);
+ // Update the collection with the queried data
+ self.collection.reset( data.themes );
+ // Trigger a collection refresh event to render the views
+ self.collection.trigger( 'update' );
+
+ console.log(self.collection);
+
+ // Un-spin it
+ $( 'body' ).removeClass( 'loading-themes' );
+ })
+ .fail( function() {
+ // Fail
+ });
+ },
+
+ activeClass: 'current',
+
+ // Overwrite search container class to append search
+ // in new location
+ searchContainer: $( '.theme-navigation' ),
+
+ uploader: function() {
+ $( 'a.upload.button' ).on( 'click', function() {
+ $( '.upload-theme' )
+ .toggleClass( 'opened' )
+ .hasClass( 'opened' ) ? $( this ).text( l10n.back ) : $( this ).text( l10n.upload );
+ });
+ },
+
+ moreFilters: function( event ) {
+ $( 'body' ).toggleClass( 'more-filters-opened' );
+ }
+ });
+
+ // Extend the main Search view
+ _.extend( themes.view.Search.prototype, {
+
+ events: {
+ 'keyup': 'search'
+ },
+
+ // Handles Ajax request for searching through themes in public repo
+ search: function() {
+ var data,
+ self = this;
+
+ this.collection = this.options.parent.view.collection;
+
+ // Clear on escape.
+ if ( event.type === 'keyup' && event.which === 27 ) {
+ event.target.value = '';
+ }
+
+ // Construct the main `search` request
+ // using the default values
+ data = _.defaults( {}, themes.orgAPI.data );
+
+ data.request['search'] = event.target.value;
+
+ // Intercept an [author] search.
+ //
+ // If input value starts with `author:` send a request
+ // for `author` instead of a regular `search`
+ if ( event.target.value.substring( 0, 7 ) === 'author:' ) {
+ data.request['search'] = '';
+ data.request['author'] = event.target.value.slice( 7 );
+ }
+
+ // Send Ajax POST request to api.wordpress.org/themes
+ $.ajax({
+ url: themes.orgAPI.url,
+
+ // We want JSON data
+ dataType: 'json',
+ type: 'POST',
+
+ // Request data
+ data: data,
+
+ beforeSend: function() {
+ // Spin it
+ $( 'body' ).addClass( 'loading-themes' );
+ }
+ })
+ .done( function( data ) {
+ // Update the collection with the queried data
+ self.collection.reset( data.themes );
+ // Trigger a collection refresh event to render the views
+ self.collection.trigger( 'update' );
+
+ // Un-spin it
+ $( 'body' ).removeClass( 'loading-themes' );
+ })
+ .fail( function() {
+ $( '#appearance' ).append( '
' );
+ });
+ }
+ });
+
+ // Set up the `theme` model with relevant action attributes
+ _.extend( themes.model.prototype, {
+
+ // Adds attributes to the defaul data coming through the .org themes api
+ // Map `id` to `slug` for shared code
+ initialize: function() {
+ var actions, install, preview;
+
+ // Install url for the theme
+ // using the install nonce
+ install = {
+ action: 'install-theme',
+ theme: this.get( 'slug' ),
+ _wpnonce: themes.data.settings._nonceInstall
+ }
+
+ // Build the url query
+ install = themes.data.settings.updateURI + '?' + $.param( install );
+
+ // Preview url for the theme
+ preview = {
+ tab: 'theme-information',
+ theme: this.get( 'slug' )
+ }
+
+ preview = themes.data.settings.installURI + '?' + $.param( preview );
+
+ // Set the attributes
+ this.set({
+ installURI: install,
+ previewURI: preview,
+ id: this.get( 'slug' )
+ });
+ }
+ });
+
+ // Store api.wordpress.org/themes values and structure
+ // for internal access
+ themes.orgAPI = {
+
+ // Default data request
+ data: {
+ action: 'query_themes',
+ request: {
+ fields: {
+ tags: true,
+ }
+ }
+ },
+
+ url: 'http://api.wordpress.org/themes/info/1.1/?action=query_themes'
+ };
+
+ // Modify routes
+ _.extend( themes.routes.prototype, {
+ routes: {
+ 'theme-install.php?theme=:slug': 'theme',
+ '': 'themes',
+ 'theme-install.php?sort=:sortBy': 'sort'
+ },
+
+ baseUrl: function( url ) {
+ return 'theme-install.php' + url;
+ }
+ });
+
+ themes.Run.extraRoutes = function() {
+ var self = this;
+ // Handles sort route events
+ themes.router.on( 'route:sort', function( sortBy ) {
+ $( '.theme-section[data-sort="' + sortBy + '"]' ).trigger( 'click' );
+ });
+ },
+
+ // Overwrite main application initializer
+ themes.Run.init = function() {
+ // Initializes the main view
+ // and bootstraps the default sorting section
+
+ // Set up the view
+ // Passes the default 'section' as an option
+ this.view = new themes.view.Appearance({
+ el: $( '#appearance' ),
+ section: 'featured'
+ });
+
+ // Render results
+ this.render();
+ }
+
+}
+
// Ready...
jQuery( document ).ready(
Index: wp-admin/css/themes.css
===================================================================
--- wp-admin/css/themes.css (revision 27274)
+++ wp-admin/css/themes.css (working copy)
@@ -25,7 +25,8 @@
margin-left: 20px;
}
-.themes-php .wrap .theme-count {
+.themes-php .wrap .theme-count,
+.theme-navigation .theme-count {
color: #fff;
-webkit-border-radius: 30px;
border-radius: 30px;
@@ -1064,158 +1065,217 @@
16.2 - Install Themes
------------------------------------------------------------------------------*/
-.theme-install-php h4 {
- margin: 2.5em 0 8px;
+.theme-install-php h2 .upload {
+ margin-left: 10px;
}
-
-.theme-install-php .tablenav {
- height: auto;
+.theme-navigation {
+ background: #fff;
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ color: #555;
+ display: inline-block;
+ font-size: 13px;
+ margin: 20px 0 30px;
+ padding: 0 20px;
+ position: relative;
+ width: 100%;
}
-
-.theme-install-php .spinner {
- margin-top: 9px;
-}
-
-.available-theme {
- display: inline-block;
- margin-right: 10px;
+.upload-theme {
+ /*background: #fff;
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);*/
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0px 0 0;
+ padding: 0;
+ width: 100%;
+ height: 0;
+ -webkit-transition: height 200ms;
+ transition: height 200ms;
overflow: hidden;
- padding: 20px 20px 20px 0;
- vertical-align: top;
- width: 300px;
+ position: relative;
+ top: 10px;
}
-
-.available-theme .screenshot {
- width: 300px;
- height: 225px;
+.upload-theme.opened {
display: block;
- border: 1px solid #ccc;
- margin-bottom: 10px;
- overflow: hidden;
- background-color: #fff;
+ height: auto;
}
-
-.available-theme img {
- width: 300px;
+.upload-theme .wp-upload-form {
+ background: #fafafa;
+ border: 1px solid #e5e5e5;
+ padding: 30px;
+ margin: 30px auto;
+ max-width: 380px;
}
-
-.available-theme h3 {
- margin: 15px 0 0;
+.upload-theme .install-help {
+ color: #999;
+ font-size: 18px;
+ font-style: normal;
+ margin: 0;
+ padding: 40px 0 0;
+ text-align: center;
}
-
-.available-theme .theme-author {
- line-height: 18px;
+.upload-theme.opened + .theme-navigation,
+.upload-theme.opened + .theme-navigation + .theme-browser {
+ display: none;
}
-
-.available-theme .action-links {
- margin-top: 10px;
- overflow: hidden;
+.theme-navigation .theme-count {
+ top: 3px;
+ margin-left: 0;
}
-
-.available-theme a.screenshot:focus {
- border-color: #777;
+.theme-section,
+.theme-filter {
+ border-bottom: 4px solid #fff;
+ color: #666;
+ cursor: pointer;
+ display: inline-block;
+ margin: 0 10px;
+ padding: 15px 0;
+ -moz-transition: border-color .1s ease-in;
+ -webkit-transition: border-color .1s ease-in;
}
-
-.available-theme .action-links li {
- float: left;
- padding-right: 10px;
- margin-right: 10px;
- border-right: 1px solid #dfdfdf;
+.theme-section.current,
+.theme-filter.current {
+ border-bottom: 4px solid #666;
+ color: #222;
}
-
-.available-theme .action-links li {
- padding-right: 8px;
- margin-right: 8px;
+.theme-top-filters {
+ display: inline-block;
+ /*padding-bottom: 4px;
+ padding-left: 20px;
+ margin-left: 20px;*/
}
-
-.ie8 .available-theme .action-links li {
- padding-right: 7px;
- margin-right: 7px;
+.theme-navigation .more-filters {
+ color: #666;
+ cursor: pointer;
+ display: inline-block;
+ margin: 0 10px;
+ padding: 4px 5px;
+ -moz-transition: color .1s ease-in;
+ -webkit-transition: color .1s ease-in, background .1s ease-in;
}
-
-.available-theme .action-links li:last-child {
- padding-right: 0;
- margin-right: 0;
- border-right: 0;
+body.more-filters-opened .more-filters,
+.theme-navigation .more-filters.current {
+ background: rgb(46, 162, 204);
+ border-radius: 2px;
+ border: none;
+ color: #fff;
}
-
-.available-theme .action-links .delete-theme {
- float: right;
- margin-left: 8px;
- margin-right: 0;
+.theme-install-php .theme-search {
+ position: absolute;
+ right: 10px;
+ top: 9px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.5;
+ width: 280px;
}
+.more-filters {
-.available-theme .action-links .delete-theme a {
- color: red;
- padding: 2px;
}
-
-.available-theme .action-links .delete-theme a:hover {
- background: red;
+.more-filters:before {
+ color: #777;
+ text-align: center;
+ margin: 0 5px 0 0;
+ content: "\f111";
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ -webkit-font-smoothing: antialiased;
+ font-size: 16px;
+ line-height: 1;
+ font-family: "dashicons";
+ text-decoration: inherit;
+ font-weight: normal;
+ font-style: normal;
+ vertical-align: top;
+ -moz-transition: color .1s ease-in 0;
+ -webkit-transition: color .1s ease-in 0;
+ text-align: center;
+}
+.more-filters.current:before {
color: #fff;
- text-decoration: none;
}
-
-.available-theme .action-links p {
- float: left;
+.more-filters-container {
+ display: none;
+ padding: 30px;
+ border-top: 1px solid #eee;
+ margin: 0 -20px;
+ background: #fafafa;
}
-
-/* Allow for three-up in small windows when sidebar is collapsed */
-@media only screen and (max-width: 1200px) {
- .folded .available-theme,
- .folded .available-theme .screenshot {
- width: 300px;
- }
-
- .folded .available-theme .screenshot {
- height: 225px;
- }
+body.more-filters-opened .more-filters-container {
+ display: block;
}
-
-/* Adjust three-up display in smaller windows when sidebar is collapsed */
-@media only screen and (max-width: 1079px) {
- .folded .available-theme,
- .folded .available-theme .screenshot {
- width: 270px;
- }
-
- .folded .available-theme .screenshot {
- height: 203px;
- }
+.theme-install-php .add-new-theme {
+ display: none !important;
}
-/* Allow for three-up on 1024px wide screens, e.g. tablets */
-@media only screen and (max-width: 1200px) {
- .available-theme,
- .available-theme .screenshot {
- width: 240px;
- }
-
- .available-theme .screenshot {
- height: 180px;
- }
-
- .available-theme img {
- width: 100%;
- }
+.rating {
+ margin: 30px 0;
}
-
-.feature-filter {
- padding: 8px 12px 0;
+.rating span:before {
+ color: #E6B800;
+ content: "\f154";
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ font: normal 20px/1 'dashicons';
+ vertical-align: top;
}
+/* Half stars */
+.rating-10 span.one:before,
+.rating-30 span.two:before,
+.rating-50 span.three:before,
+.rating-70 span.four:before,
+.rating-90 span.five:before {
+ content: "\f459";
+}
+/* Full stars */
+.rating-20 span.one:before {
+ content: "\f155";
+}
+.rating-30 span.one:before,
+.rating-40 span.one:before,
+.rating-40 span.two:before {
+ content: "\f155";
+}
+.rating-50 span.one:before,
+.rating-50 span.two:before,
+.rating-60 span.one:before,
+.rating-60 span.two:before,
+.rating-60 span.three:before {
+ content: "\f155";
+}
+.rating-70 span.one:before,
+.rating-70 span.two:before,
+.rating-70 span.three:before,
+.rating-80 span.one:before,
+.rating-80 span.two:before,
+.rating-80 span.three:before,
+.rating-80 span.four:before {
+ content: "\f155";
+}
-.feature-filter .feature-group {
- float: left;
- margin: 5px 10px 10px;
+.rating-90 span.one:before,
+.rating-90 span.two:before,
+.rating-90 span.three:before,
+.rating-90 span.four:before,
+.rating-100 span.one:before,
+.rating-100 span.two:before,
+.rating-100 span.three:before,
+.rating-100 span.four:before,
+.rating-100 span.five:before {
+ content: "\f155";
}
-.feature-filter .feature-group li {
- display: inline-block;
- vertical-align: top;
- list-style-type: none;
- padding-right: 25px;
- width: 150px;
+.loading-themes .theme-browser,
+.error .theme-browser {
+ display: none;
}
+.loading-themes .spinner {
+ display: block;
+ margin: 40px auto 0;
+ float: none;
+}
/*------------------------------------------------------------------------------
16.3 - Custom Header Screen
Index: wp-admin/theme-install.php
===================================================================
--- wp-admin/theme-install.php (revision 27274)
+++ wp-admin/theme-install.php (working copy)
@@ -20,20 +20,52 @@
exit();
}
-$wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
-$pagenum = $wp_list_table->get_pagenum();
-$wp_list_table->prepare_items();
+// $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
+// $pagenum = $wp_list_table->get_pagenum();
+// $wp_list_table->prepare_items();
-$title = __('Install Themes');
+$title = __( 'Add Themes' );
$parent_file = 'themes.php';
-if ( !is_network_admin() )
+
+if ( ! is_network_admin() ) {
$submenu_file = 'themes.php';
+}
-wp_enqueue_script( 'theme-install' );
+// wp_enqueue_script( 'theme-install' );
wp_enqueue_script( 'theme-preview' );
-$body_id = $tab;
+wp_localize_script( 'theme', '_wpThemeSettings', array(
+ 'themes' => false,
+ 'settings' => array(
+ 'isBrowsing' => (bool) ( get_current_screen()->id == 'theme-install' ),
+ 'canInstall' => ( ! is_multisite() && current_user_can( 'install_themes' ) ),
+ 'installURI' => ( ! is_multisite() && current_user_can( 'install_themes' ) ) ? admin_url( 'theme-install.php' ) : null,
+ 'adminUrl' => parse_url( admin_url(), PHP_URL_PATH ),
+ 'updateURI' => admin_url( 'update.php' ),
+ '_nonceInstall' => wp_create_nonce( 'install-theme' )
+ ),
+ 'l10n' => array(
+ 'addNew' => __( 'Add New Theme' ),
+ 'search' => __( 'Search Themes' ),
+ 'searchPlaceholder' => __( 'Search themes...' ),
+ 'upload' => __( 'Upload Theme' ),
+ 'back' => __( 'Back' ),
+ 'error' => __( 'There was a problem trying to load the themes. Please, try again.' ),
+ ),
+ 'browse' => array(
+ 'sections' => apply_filters( 'install_theme_sections', array(
+ 'featured' => __( 'Featured Themes' ),
+ 'popular' => __( 'Popular Themes' ),
+ 'new' => __( 'Newest Themes' ),
+ ) ),
+ 'publicThemes' => ( get_current_screen()->id == 'theme-install' ) ? prepare_public_themes_for_js() : null,
+ ),
+) );
+wp_enqueue_script( 'theme' );
+
+// $body_id = $tab;
+
/**
* Fires before each of the tabs are rendered on the Install Themes page.
*
@@ -43,7 +75,7 @@
*
* @since 2.8.0
*/
-do_action( "install_themes_pre_{$tab}" );
+// do_action( "install_themes_pre_{$tab}" );
$help_overview =
'' . sprintf(__('You can find additional themes for your site by using the Theme Browser/Installer on this screen, which will display themes from the WordPress.org Theme Directory . These themes are designed and developed by third parties, are available free of charge, and are compatible with the license WordPress uses.'), 'http://wordpress.org/themes/') . '
' .
@@ -73,14 +105,52 @@
);
include(ABSPATH . 'wp-admin/admin-header.php');
+
+/**
+ * Uploader
+ */
+function install_themes_upload() {
+ ?>
+
+
-
-
-
+
+
+
+
-$wp_list_table->views(); ?>
+
-
+
+
+
+
+
+
+ Photography
+ Responsive
+ More
+
+
+ Display more filters.
+
+
+
+
+
+
+
+
+
+
+
+
+