Ticket #27055: 27055.9.diff
| File 27055.9.diff, 31.5 KB (added by , 12 years ago) |
|---|
-
src/wp-admin/css/themes.css
diff --git src/wp-admin/css/themes.css src/wp-admin/css/themes.css index 329d546..54d00a0 100644
25 25 margin-left: 20px; 26 26 } 27 27 28 .themes-php .wrap .theme-count { 28 .themes-php .wrap .theme-count, 29 .theme-navigation .theme-count { 29 30 color: #fff; 30 31 -webkit-border-radius: 30px; 31 32 border-radius: 30px; … … body.folded .theme-overlay .theme-wrap { 1064 1065 16.2 - Install Themes 1065 1066 ------------------------------------------------------------------------------*/ 1066 1067 1067 .theme-install-php h4 { 1068 margin: 2.5em 0 8px; 1069 } 1070 1071 .theme-install-php .tablenav { 1072 height: auto; 1073 } 1074 1075 .theme-install-php .spinner { 1076 margin-top: 9px; 1068 .theme-install-php h2 .upload { 1069 margin-left: 10px; 1077 1070 } 1078 1079 .available-theme { 1071 .theme-navigation { 1072 background: #fff; 1073 box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); 1074 -moz-box-sizing: border-box; 1075 box-sizing: border-box; 1076 color: #555; 1080 1077 display: inline-block; 1081 margin-right: 10px;1082 overflow: hidden;1083 padding: 20px 20px 20px 0;1084 vertical-align: top;1085 width: 300px;1078 font-size: 13px; 1079 margin: 20px 0 30px; 1080 padding: 0 20px; 1081 position: relative; 1082 width: 100%; 1086 1083 } 1087 1088 .available-theme .screenshot { 1089 width: 300px;1090 height: 225px;1091 display: block;1092 border: 1px solid #ccc;1093 margin-bottom: 10px;1084 .upload-theme { 1085 -moz-box-sizing: border-box; 1086 box-sizing: border-box; 1087 display: none; 1088 margin: 0px 0 0; 1089 padding: 0; 1090 width: 100%; 1094 1091 overflow: hidden; 1095 background-color: #fff; 1092 position: relative; 1093 top: 10px; 1096 1094 } 1097 1098 .available-theme img { 1099 width: 300px; 1095 .upload-theme.opened { 1096 display: block; 1100 1097 } 1101 1102 .available-theme h3 { 1103 margin: 15px 0 0; 1098 .upload-theme .wp-upload-form { 1099 background: #fafafa; 1100 border: 1px solid #e5e5e5; 1101 padding: 30px; 1102 margin: 30px auto; 1103 max-width: 380px; 1104 1104 } 1105 1106 .available-theme .theme-author { 1107 line-height: 18px; 1105 .upload-theme .install-help { 1106 color: #999; 1107 font-size: 18px; 1108 font-style: normal; 1109 margin: 0; 1110 padding: 40px 0 0; 1111 text-align: center; 1108 1112 } 1109 1110 .available-theme .action-links { 1111 margin-top: 10px; 1112 overflow: hidden; 1113 .upload-theme.opened + .theme-navigation, 1114 .upload-theme.opened + .theme-navigation + .theme-browser { 1115 display: none; 1113 1116 } 1114 1115 .available-theme a.screenshot:focus { 1116 border-color: #777;1117 .theme-navigation .theme-count { 1118 top: 3px; 1119 margin-left: 0; 1117 1120 } 1118 1119 .available-theme .action-links li { 1120 float: left; 1121 padding-right: 10px; 1122 margin-right: 10px; 1123 border-right: 1px solid #dfdfdf; 1121 .theme-section, 1122 .theme-filter { 1123 border-bottom: 4px solid #fff; 1124 color: #666; 1125 cursor: pointer; 1126 display: inline-block; 1127 margin: 0 10px; 1128 padding: 15px 0; 1129 -moz-transition: border-color .1s ease-in; 1130 -webkit-transition: border-color .1s ease-in; 1124 1131 } 1125 1126 . available-theme .action-links li{1127 padding-right: 8px;1128 margin-right: 8px;1132 .theme-section.current, 1133 .theme-filter.current { 1134 border-bottom: 4px solid #666; 1135 color: #222; 1129 1136 } 1130 1131 .ie8 .available-theme .action-links li { 1132 padding-right: 7px; 1133 margin-right: 7px; 1137 .theme-top-filters { 1138 display: inline-block; 1134 1139 } 1135 1136 .available-theme .action-links li:last-child { 1137 padding-right: 0; 1138 margin-right: 0; 1139 border-right: 0; 1140 .theme-navigation .more-filters { 1141 color: #666; 1142 cursor: pointer; 1143 display: inline-block; 1144 margin: 0 10px; 1145 padding: 4px 5px; 1146 -moz-transition: color .1s ease-in, background .1s ease-in; 1147 -webkit-transition: color .1s ease-in, background .1s ease-in; 1148 transition: color .1s ease-in, background .1s ease-in; 1149 } 1150 body.more-filters-opened .more-filters, 1151 .theme-navigation .more-filters.current { 1152 background: rgb(46, 162, 204); 1153 border-radius: 2px; 1154 border: none; 1155 color: #fff; 1140 1156 } 1141 1142 .available-theme .action-links .delete-theme { 1143 float: right; 1144 margin-left: 8px; 1145 margin-right: 0; 1157 .theme-install-php .theme-search { 1158 position: absolute; 1159 right: 10px; 1160 top: 9px; 1161 font-size: 16px; 1162 font-weight: 300; 1163 line-height: 1.5; 1164 width: 280px; 1146 1165 } 1147 1148 .available-theme .action-links .delete-theme a { 1149 color: red; 1150 padding: 2px; 1166 .more-filters:before { 1167 color: #777; 1168 text-align: center; 1169 margin: 0 5px 0 0; 1170 content: "\f111"; 1171 display: inline-block; 1172 width: 16px; 1173 height: 16px; 1174 -webkit-font-smoothing: antialiased; 1175 font-size: 16px; 1176 line-height: 1; 1177 font-family: "dashicons"; 1178 text-decoration: inherit; 1179 font-weight: normal; 1180 font-style: normal; 1181 vertical-align: top; 1182 -moz-transition: color .1s ease-in 0; 1183 -webkit-transition: color .1s ease-in 0; 1184 transition: color .1s ease-in 0; 1185 text-align: center; 1151 1186 } 1152 1153 .available-theme .action-links .delete-theme a:hover { 1154 background: red; 1187 .more-filters.current:before { 1155 1188 color: #fff; 1156 text-decoration: none;1157 }1158 1159 .available-theme .action-links p {1160 float: left;1161 }1162 1163 /* Allow for three-up in small windows when sidebar is collapsed */1164 @media only screen and (max-width: 1200px) {1165 .folded .available-theme,1166 .folded .available-theme .screenshot {1167 width: 300px;1168 }1169 1170 .folded .available-theme .screenshot {1171 height: 225px;1172 }1173 1189 } 1174 1175 /* Adjust three-up display in smaller windows when sidebar is collapsed */ 1176 @media only screen and (max-width: 1079px) { 1177 .folded .available-theme, 1178 .folded .available-theme .screenshot { 1179 width: 270px; 1180 } 1181 1182 .folded .available-theme .screenshot { 1183 height: 203px; 1184 } 1190 .more-filters-container { 1191 display: none; 1192 padding: 30px; 1193 border-top: 1px solid #eee; 1194 margin: 0 -20px; 1195 background: #fafafa; 1185 1196 } 1186 1187 /* Allow for three-up on 1024px wide screens, e.g. tablets */ 1188 @media only screen and (max-width: 1200px) { 1189 .available-theme, 1190 .available-theme .screenshot { 1191 width: 240px; 1192 } 1193 1194 .available-theme .screenshot { 1195 height: 180px; 1196 } 1197 1198 .available-theme img { 1199 width: 100%; 1200 } 1197 body.more-filters-opened .more-filters-container { 1198 display: block; 1201 1199 } 1202 1203 .feature-filter { 1204 padding: 8px 12px 0; 1200 .theme-install-php .add-new-theme { 1201 display: none !important; 1205 1202 } 1206 1203 1207 .feature-filter .feature-group { 1208 float: left; 1209 margin: 5px 10px 10px; 1204 .rating { 1205 margin: 30px 0; 1210 1206 } 1211 1212 .feature-filter .feature-group li { 1207 .rating span:before { 1208 color: #e6b800; 1209 content: "\f154"; 1213 1210 display: inline-block; 1211 -webkit-font-smoothing: antialiased; 1212 font: normal 20px/1 'dashicons'; 1214 1213 vertical-align: top; 1215 list-style-type: none; 1216 padding-right: 25px; 1217 width: 150px; 1214 } 1215 /* Half stars */ 1216 .rating-10 span.one:before, 1217 .rating-30 span.two:before, 1218 .rating-50 span.three:before, 1219 .rating-70 span.four:before, 1220 .rating-90 span.five:before { 1221 content: "\f459"; 1222 } 1223 /* Full stars */ 1224 .rating-20 span.one:before { 1225 content: "\f155"; 1226 } 1227 .rating-30 span.one:before, 1228 .rating-40 span.one:before, 1229 .rating-40 span.two:before { 1230 content: "\f155"; 1231 } 1232 .rating-50 span.one:before, 1233 .rating-50 span.two:before, 1234 .rating-60 span.one:before, 1235 .rating-60 span.two:before, 1236 .rating-60 span.three:before { 1237 content: "\f155"; 1238 } 1239 .rating-70 span.one:before, 1240 .rating-70 span.two:before, 1241 .rating-70 span.three:before, 1242 .rating-80 span.one:before, 1243 .rating-80 span.two:before, 1244 .rating-80 span.three:before, 1245 .rating-80 span.four:before { 1246 content: "\f155"; 1247 } 1248 .rating-90 span.one:before, 1249 .rating-90 span.two:before, 1250 .rating-90 span.three:before, 1251 .rating-90 span.four:before, 1252 .rating-100 span.one:before, 1253 .rating-100 span.two:before, 1254 .rating-100 span.three:before, 1255 .rating-100 span.four:before, 1256 .rating-100 span.five:before { 1257 content: "\f155"; 1258 } 1259 .rating .votes { 1260 display: inline; 1261 margin-left: 10px; 1262 line-height: 20px; 1263 } 1264 .loading-themes .theme-browser, 1265 .error .theme-browser { 1266 display: none; 1267 } 1268 .loading-themes .spinner { 1269 display: block; 1270 margin: 40px auto 0; 1271 float: none; 1218 1272 } 1219 1273 1220 1274 /*------------------------------------------------------------------------------ -
src/wp-admin/includes/theme.php
diff --git src/wp-admin/includes/theme.php src/wp-admin/includes/theme.php index 9e06596..e5bf43a 100644
function wp_prepare_themes_for_js( $themes = null ) { 453 453 */ 454 454 $prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes ); 455 455 return array_values( $prepared_themes ); 456 } 457 458 459 /** 460 * Get public themes from the themes directory 461 * and prepare them for JavaScript 462 * 463 * @since 3.8.0 464 * 465 * @uses themes_api themes_directory_sections 466 * @return array with $theme objects 467 */ 468 function prepare_public_themes_for_js( $themes = array() ) { 469 470 $sections = array( 471 'featured' => __( 'Featured Themes' ), 472 'popular' => __( 'Popular Themes' ), 473 'new' => __( 'Newest Themes' ), 474 ); 475 476 $sections = array_keys( $sections ); 477 478 $args = array( 479 'page' => 1, 480 'per_page' => 24, 481 ); 482 483 foreach ( $sections as $section ) { 484 $args['browse'] = $section; 485 $themes[ $section ] = themes_api( 'query_themes', $args ); 486 } 487 488 return $themes; 456 489 } 490 No newline at end of file -
src/wp-admin/js/theme.js
diff --git src/wp-admin/js/theme.js src/wp-admin/js/theme.js index 7e12958..28339cf 100644
themes = wp.themes = wp.themes || {}; 12 12 themes.data = _wpThemeSettings; 13 13 l10n = themes.data.l10n; 14 14 15 // Shortcut for (bool) isBrowsing check 16 themes.isInstall = themes.data.settings.isBrowsing; 17 15 18 // Setup app structure 16 _.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template });19 _.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template, orgAPI: {} }); 17 20 18 themes.model = Backbone.Model.extend({}); 21 themes.Model = Backbone.Model.extend({ 22 // Adds attributes to the defaul data coming through the .org themes api 23 // Map `id` to `slug` for shared code 24 initialize: function() { 25 var install, preview; 26 27 // Install url for the theme 28 // using the install nonce 29 install = { 30 action: 'install-theme', 31 theme: this.get( 'slug' ), 32 _wpnonce: themes.data.settings._nonceInstall 33 }; 34 35 // Build the url query 36 install = themes.data.settings.updateURI + '?' + $.param( install ); 37 38 // Preview url for the theme 39 preview = { 40 tab: 'theme-information', 41 theme: this.get( 'slug' ) 42 }; 43 44 preview = themes.data.settings.installURI + '?' + $.param( preview ); 45 46 // Set the attributes 47 this.set({ 48 installURI: install, 49 previewURI: preview, 50 id: this.get( 'slug' ) 51 }); 52 } 53 }); 19 54 20 55 // Main view controller for themes.php 21 56 // Unifies and renders all available views … … themes.view.Appearance = wp.Backbone.View.extend({ 28 63 page: 0, 29 64 30 65 // Sets up a throttler for binding to 'scroll' 31 initialize: function( ) {66 initialize: function( options ) { 32 67 // Scroller checks how far the scroll position is 33 68 _.bindAll( this, 'scroller' ); 34 69 70 this.SearchView = options.SearchView ? options.SearchView : themes.view.Search; 35 71 // Bind to the scroll event and throttle 36 72 // the results from this.scroller 37 73 this.window.bind( 'scroll', _.throttle( this.scroller, 300 ) ); … … themes.view.Appearance = wp.Backbone.View.extend({ 55 91 this.$el.append( '<br class="clear"/>' ); 56 92 }, 57 93 94 // Defines search element container 95 searchContainer: $( '#wpbody h2:first' ), 96 58 97 // Search input and view 59 98 // for current theme collection 60 99 search: function() { … … themes.view.Appearance = wp.Backbone.View.extend({ 66 105 return; 67 106 } 68 107 69 view = new themes.view.Search({ collection: self.collection, parent: this }); 108 view = new this.SearchView({ 109 collection: self.collection, 110 parent: this 111 }); 70 112 71 113 // Render and append after screen title 72 114 view.render(); 73 $('#wpbody h2:first')115 this.searchContainer 74 116 .append( $.parseHTML( '<label class="screen-reader-text" for="theme-search-input">' + l10n.search + '</label>' ) ) 75 117 .append( view.el ); 76 118 }, … … themes.view.Appearance = wp.Backbone.View.extend({ 95 137 // @has 'id' 'name' 'screenshot' 'author' 'authorURI' 'version' 'active' ... 96 138 themes.Collection = Backbone.Collection.extend({ 97 139 98 model: themes. model,140 model: themes.Model, 99 141 100 142 // Search terms 101 143 terms: '', … … themes.view.Theme = wp.Backbone.View.extend({ 188 230 189 231 events: { 190 232 'click': 'expand', 233 'click .preview': 'preview', 191 234 'keydown': 'expand', 192 235 'touchend': 'expand', 193 236 'touchmove': 'preventExpand' … … themes.view.Theme = wp.Backbone.View.extend({ 250 293 251 294 preventExpand: function() { 252 295 this.touchDrag = true; 296 }, 297 298 preview: function( event ) { 299 event.preventDefault(); 300 301 event = event || window.event; 302 303 var preview = new themes.view.Preview({ 304 model: this.model 305 }); 306 307 preview.render(); 308 $( '#appearance' ).append( preview.el ); 253 309 } 254 310 }); 255 311 … … themes.view.Details = wp.Backbone.View.extend({ 415 471 } 416 472 }); 417 473 474 // Theme Preview view 475 // Set ups a modal overlay with the expanded theme data 476 themes.view.Preview = wp.Backbone.View.extend({ 477 478 className: 'wp-full-overlay expanded', 479 el: '#theme-installer', 480 481 events: { 482 'click .close-full-overlay': 'close', 483 'click .collapse-sidebar': 'collapse' 484 }, 485 486 // The HTML template for the theme preview 487 html: themes.template( 'theme-preview' ), 488 489 render: function() { 490 var data = this.model.toJSON(); 491 this.$el.html( this.html( data ) ); 492 493 themes.router.navigate( themes.router.baseUrl( '?preview=' + this.model.get( 'id' ) ), { replace: true } ); 494 495 this.$el.fadeIn( 200, function() { 496 $( 'body' ).addClass( 'theme-installer-active full-overlay-active' ); 497 }); 498 }, 499 500 close: function() { 501 this.$el.fadeOut( 200, function() { 502 $( 'body' ).removeClass( 'theme-installer-active full-overlay-active' ); 503 }); 504 505 themes.router.navigate( themes.router.baseUrl( '' ) ); 506 }, 507 508 collapse: function() { 509 this.$el.toggleClass( 'collapsed' ).toggleClass( 'expanded' ); 510 } 511 }); 512 418 513 // Controls the rendering of div.themes, 419 514 // a wrapper that will hold all the theme elements 420 515 themes.view.Themes = wp.Backbone.View.extend({ … … themes.view.Search = wp.Backbone.View.extend({ 732 827 733 828 // Sets up the routes events for relevant url queries 734 829 // Listens to [theme] and [search] params 735 themes. routes= Backbone.Router.extend({830 themes.Router = Backbone.Router.extend({ 736 831 737 832 routes: { 738 833 'themes.php?theme=:slug': 'theme', … … themes.Run = { 788 883 var self = this; 789 884 // Bind to our global thx object 790 885 // so that the object is available to sub-views 791 themes.router = new themes. routes();886 themes.router = new themes.Router(); 792 887 793 888 // Handles theme details route event 794 889 themes.router.on( 'route:theme', function( slug ) { … … themes.Run = { 805 900 self.view.trigger( 'theme:close' ); 806 901 self.themes.doSearch( query ); 807 902 }); 903 904 this.extraRoutes(); 905 }, 906 907 extraRoutes: function() { 908 return false; 808 909 } 809 910 }; 810 911 811 // Ready... 812 jQuery( document ).ready( 912 // Extend the main Search view 913 themes.view.InstallerSearch = themes.view.Search.extend({ 914 915 events: { 916 'keyup': 'search' 917 }, 918 919 // Handles Ajax request for searching through themes in public repo 920 search: function( event ) { 921 var data, 922 self = this; 813 923 814 // Bring on the themes 815 _.bind( themes.Run.init, themes.Run ) 924 this.collection = this.options.parent.view.collection; 925 926 // Clear on escape. 927 if ( event.type === 'keyup' && event.which === 27 ) { 928 event.target.value = ''; 929 } 930 931 // Construct the main `search` request 932 // using the default values 933 data = _.defaults( {}, themes.orgAPI.data ); 934 935 data.request.search = event.target.value; 936 937 // Intercept an [author] search. 938 // 939 // If input value starts with `author:` send a request 940 // for `author` instead of a regular `search` 941 if ( event.target.value.substring( 0, 7 ) === 'author:' ) { 942 data.request.search = ''; 943 data.request.author = event.target.value.slice( 7 ); 944 } 945 946 // Intercept a [tag] search. 947 // 948 // If input value starts with `tag:` send a request 949 // for `tag` instead of a regular `search` 950 if ( event.target.value.substring( 0, 4 ) === 'tag:' ) { 951 data.request.search = ''; 952 data.request.tag = [ event.target.value.slice( 4 ) ]; 953 } 954 955 // Send Ajax POST request to api.wordpress.org/themes 956 $.ajax({ 957 url: themes.orgAPI.url, 958 959 // We want JSON data 960 dataType: 'json', 961 type: 'POST', 962 crossDomain: true, 963 964 // Request data 965 data: data, 966 967 beforeSend: function() { 968 // Spin it 969 $( 'body' ).addClass( 'loading-themes' ); 970 } 971 }) 972 .done( function( data ) { 973 // Update the collection with the queried data 974 self.collection.reset( data.themes ); 975 // Trigger a collection refresh event to render the views 976 self.collection.trigger( 'update' ); 977 978 // Un-spin it 979 $( 'body' ).removeClass( 'loading-themes' ); 980 $( '#appearance' ).find( 'div.error' ).remove(); 981 }) 982 .fail( function() { 983 $( '#appearance' ).find( 'div.error' ).remove(); 984 $( '#appearance' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' ); 985 }); 986 987 return false; 988 } 989 }); 990 991 // Store api.wordpress.org/themes values and structure 992 // for internal access 993 themes.orgAPI = { 994 995 // Default data request 996 data: { 997 action: 'query_themes', 998 request: {} 999 }, 1000 1001 url: 'https://api.wordpress.org/themes/info/1.1/?action=query_themes' 1002 }; 1003 1004 themes.view.Installer = themes.view.Appearance.extend({ 1005 1006 el: '#wpbody-content .wrap', 1007 1008 // Register events for sorting and filters in theme-navigation 1009 events: { 1010 'click .theme-section': 'onSort', 1011 'click .theme-filter': 'onFilter', 1012 'click .more-filters': 'moreFilters' 1013 }, 1014 1015 // Handles all the rendering of the public theme directory 1016 browse: function( section ) { 1017 // Create a new collection with the proper theme data 1018 // for each section 1019 this.collection = new themes.Collection( themes.data.browse.publicThemes[ section ].themes ); 1020 1021 if ( this.view ) { 1022 this.view.remove(); 1023 } 1024 1025 // Set ups the view and passes the section argument 1026 this.view = new themes.view.Themes({ 1027 collection: this.collection, 1028 section: section, 1029 parent: this 1030 }); 1031 1032 // Reset pagination every time the install view handler is run 1033 this.page = 0; 1034 1035 // Render and append 1036 this.$el.find( '.themes' ).remove(); 1037 this.view.render(); 1038 this.$el.find( '.theme-browser' ).append( this.view.el ); 1039 1040 this.uploader(); 1041 }, 816 1042 817 ); 1043 // Initial render method 1044 render: function() { 1045 this.search(); 1046 return this.browse( this.options.section ); 1047 }, 1048 1049 // Sorting navigation 1050 onSort: function( event ) { 1051 var $el = $( event.target ), 1052 sort = $el.data( 'sort' ); 1053 1054 // Bail if this is already active 1055 if ( $el.hasClass( this.activeClass ) ) { 1056 return; 1057 } 1058 1059 this.sort( sort ); 1060 1061 // Trigger a router.naviagte update 1062 themes.router.navigate( themes.router.baseUrl( '?sort=' + sort ) ); 1063 }, 1064 1065 sort: function( sort ) { 1066 $( '#theme-search-input' ).val( '' ); 1067 1068 $( '.theme-section, .theme-filter' ).removeClass( this.activeClass ); 1069 $( '[data-sort="' + sort + '"]' ).addClass( this.activeClass ); 1070 1071 this.browse( sort ); 1072 }, 1073 1074 // Filters and Tags 1075 onFilter: function( event ) { 1076 var $el = $( event.target ), 1077 filter = $el.data( 'filter' ), 1078 self = this, 1079 data; 1080 1081 // Bail if this is already active 1082 if ( $el.hasClass( this.activeClass ) ) { 1083 return; 1084 } 1085 1086 $( '.theme-filter, .theme-section' ).removeClass( this.activeClass ); 1087 $el.addClass( this.activeClass ); 1088 1089 if ( ! filter ) { 1090 return; 1091 } 1092 1093 // Construct the filter request 1094 // using the default values 1095 data = _.defaults( {}, themes.orgAPI.data ); 1096 1097 data.request = _.defaults({ 1098 tag: [ filter ] 1099 }, themes.orgAPI.data.request ); 1100 1101 // Send Ajax POST request to api.wordpress.org/themes 1102 $.ajax({ 1103 url: themes.orgAPI.url, 1104 1105 // We want JSON data 1106 dataType: 'json', 1107 type: 'POST', 1108 crossDomain: true, 1109 1110 // Request data 1111 data: data, 1112 1113 beforeSend: function() { 1114 // Spin it 1115 $( 'body' ).addClass( 'loading-themes' ); 1116 } 1117 }) 1118 .done( function( data ) { 1119 // Update the collection with the queried data 1120 self.collection.reset( data.themes ); 1121 // Trigger a collection refresh event to render the views 1122 self.collection.trigger( 'update' ); 1123 1124 // Un-spin it 1125 $( 'body' ).removeClass( 'loading-themes' ); 1126 $( '#appearance' ).find( 'div.error' ).remove(); 1127 }) 1128 .fail( function() { 1129 $( '#appearance' ).find( 'div.error' ).remove(); 1130 $( '#appearance' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' ); 1131 }); 1132 1133 return false; 1134 }, 1135 1136 activeClass: 'current', 1137 1138 // Overwrite search container class to append search 1139 // in new location 1140 searchContainer: $( '.theme-navigation' ), 1141 1142 uploader: function() { 1143 $( 'a.upload.button' ).on( 'click', function() { 1144 $( '.upload-theme' ) 1145 .toggleClass( 'opened' ) 1146 .hasClass( 'opened' ) ? $( this ).text( l10n.back ) : $( this ).text( l10n.upload ); 1147 }); 1148 }, 1149 1150 moreFilters: function() { 1151 $( 'body' ).toggleClass( 'more-filters-opened' ); 1152 } 1153 }); 1154 1155 themes.InstallerRouter = Backbone.Router.extend({ 1156 routes: { 1157 'theme-install.php?theme=:slug': 'theme', 1158 '': 'sort', 1159 'theme-install.php(?sort=:sort)': 'sort', 1160 'theme-install.php?preview=:slug': 'preview' 1161 }, 1162 1163 baseUrl: function( url ) { 1164 return 'theme-install.php' + url; 1165 } 1166 }); 1167 1168 1169 themes.RunInstaller = { 1170 1171 init: function() { 1172 // Set up the view 1173 // Passes the default 'section' as an option 1174 this.view = new themes.view.Installer({ 1175 el: $( '#appearance' ), 1176 section: 'featured', 1177 SearchView: themes.view.InstallerSearch 1178 }); 1179 1180 // Render results 1181 this.render(); 1182 1183 }, 1184 1185 render: function() { 1186 1187 // Render results 1188 this.view.render(); 1189 this.routes(); 1190 1191 Backbone.history.start({ 1192 root: themes.data.settings.adminUrl, 1193 pushState: true, 1194 hashChange: false 1195 }); 1196 }, 1197 1198 routes: function() { 1199 var self = this; 1200 // Bind to our global thx object 1201 // so that the object is available to sub-views 1202 themes.router = new themes.InstallerRouter(); 1203 1204 // Handles theme details route event 1205 themes.router.on( 'route:theme', function( slug ) { 1206 self.view.view.expand( slug ); 1207 }); 1208 1209 themes.router.on( 'route:sort', function( sort ) { 1210 if ( ! sort ) { 1211 sort = 'featured'; 1212 } 1213 self.view.sort( sort ); 1214 self.view.trigger( 'theme:close' ); 1215 }); 1216 1217 this.extraRoutes(); 1218 }, 1219 1220 extraRoutes: function() { 1221 return false; 1222 } 1223 }; 1224 1225 // Ready... 1226 $( document ).ready(function() { 1227 if ( themes.isInstall ) { 1228 themes.RunInstaller.init(); 1229 } else { 1230 themes.Run.init(); 1231 } 1232 }); 818 1233 819 1234 })( jQuery ); 820 1235 -
src/wp-admin/theme-install.php
diff --git src/wp-admin/theme-install.php src/wp-admin/theme-install.php index 7cb2a9a..28a2e71 100644
if ( is_multisite() && ! is_network_admin() ) { 20 20 exit(); 21 21 } 22 22 23 $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');24 $pagenum = $wp_list_table->get_pagenum();25 $wp_list_table->prepare_items();23 // $wp_list_table = _get_list_table('WP_Theme_Install_List_Table'); 24 // $pagenum = $wp_list_table->get_pagenum(); 25 // $wp_list_table->prepare_items(); 26 26 27 $title = __( 'Install Themes');27 $title = __( 'Add Themes' ); 28 28 $parent_file = 'themes.php'; 29 if ( !is_network_admin() ) 29 30 if ( ! is_network_admin() ) { 30 31 $submenu_file = 'themes.php'; 32 } 31 33 32 wp_enqueue_script( 'theme-install' );34 // wp_enqueue_script( 'theme-install' ); 33 35 wp_enqueue_script( 'theme-preview' ); 34 36 35 $body_id = $tab; 37 wp_localize_script( 'theme', '_wpThemeSettings', array( 38 'themes' => false, 39 'settings' => array( 40 'isBrowsing' => (bool) ( get_current_screen()->id == 'theme-install' ), 41 'canInstall' => ( ! is_multisite() && current_user_can( 'install_themes' ) ), 42 'installURI' => ( ! is_multisite() && current_user_can( 'install_themes' ) ) ? admin_url( 'theme-install.php' ) : null, 43 'adminUrl' => parse_url( admin_url(), PHP_URL_PATH ), 44 'updateURI' => admin_url( 'update.php' ), 45 '_nonceInstall' => wp_create_nonce( 'install-theme' ) 46 ), 47 'l10n' => array( 48 'addNew' => __( 'Add New Theme' ), 49 'search' => __( 'Search Themes' ), 50 'searchPlaceholder' => __( 'Search themes...' ), 51 'upload' => __( 'Upload Theme' ), 52 'back' => __( 'Back' ), 53 'error' => __( 'There was a problem trying to load the themes. Please, try again.' ), 54 ), 55 'browse' => array( 56 'sections' => apply_filters( 'install_theme_sections', array( 57 'featured' => __( 'Featured Themes' ), 58 'popular' => __( 'Popular Themes' ), 59 'new' => __( 'Newest Themes' ), 60 ) ), 61 'publicThemes' => ( get_current_screen()->id == 'theme-install' ) ? prepare_public_themes_for_js() : null, 62 ), 63 ) ); 64 65 wp_enqueue_script( 'theme' ); 66 67 // $body_id = $tab; 36 68 37 69 /** 38 70 * Fires before each of the tabs are rendered on the Install Themes page. … … $body_id = $tab; 43 75 * 44 76 * @since 2.8.0 45 77 */ 46 do_action( "install_themes_pre_{$tab}" );78 // do_action( "install_themes_pre_{$tab}" ); 47 79 48 80 $help_overview = 49 81 '<p>' . sprintf(__('You can find additional themes for your site by using the Theme Browser/Installer on this screen, which will display themes from the <a href="%s" target="_blank">WordPress.org Theme Directory</a>. These themes are designed and developed by third parties, are available free of charge, and are compatible with the license WordPress uses.'), 'https://wordpress.org/themes/') . '</p>' . … … get_current_screen()->set_help_sidebar( 73 105 ); 74 106 75 107 include(ABSPATH . 'wp-admin/admin-header.php'); 108 109 /** 110 * Uploader 111 */ 112 function install_themes_upload() { 113 ?> 114 <div class="upload-theme"> 115 <p class="install-help"><?php _e( 'If you have a theme in a .zip format, you may install it by uploading it here.' ); ?></p> 116 <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-theme'); ?>"> 117 <?php wp_nonce_field( 'theme-upload'); ?> 118 <input type="file" name="themezip" /> 119 <?php submit_button( __( 'Install Now' ), 'button', 'install-theme-submit', false ); ?> 120 </form> 121 </div> 122 <?php 123 } 124 add_action( 'install_themes_upload', 'install_themes_upload', 10, 1 ); 125 76 126 ?> 77 <div class="wrap"> 78 <h2><?php echo esc_html( $title ); ?></h2> 79 <?php 127 <div id="appearance" class="wrap"> 128 <h2> 129 <?php echo esc_html( $title ); ?> 130 <a class="upload button button-secondary"><?php esc_html_e( 'Upload Theme' ); ?></a> 131 </h2> 132 133 <?php install_themes_upload(); ?> 134 135 <div class="theme-navigation"> 136 <span class="theme-count"></span> 137 <span class="theme-section current" data-sort="featured"><?php esc_html_e( 'Featured' ); ?></span> 138 <span class="theme-section" data-sort="popular"><?php esc_html_e( 'Popular' ); ?></span> 139 <span class="theme-section" data-sort="new"><?php esc_html_e( 'Latest' ); ?></span> 140 <div class="theme-top-filters"> 141 <span class="theme-filter" data-filter="photoblogging">Photography</span> 142 <span class="theme-filter" data-filter="responsive-layout">Responsive</span> 143 <span class="theme-filter more-filters">More</span> 144 </div> 145 <div class="more-filters-container"> 146 Display more filters. 147 </div> 148 </div> 149 <div class="theme-browser"></div> 150 <div class="theme-overlay"></div> 151 <div id="theme-installer" class="wp-full-overlay expanded"></div> 80 152 81 $wp_list_table->views(); ?>153 <span class="spinner"></span> 82 154 83 <br class="clear" />155 <br class="clear" /> 84 156 <?php 85 157 /** 86 158 * Fires at the top of each of the tabs on the Install Themes page. … … $wp_list_table->views(); ?> 93 165 * 94 166 * @param int $paged Number of the current page of results being viewed. 95 167 */ 96 do_action( "install_themes_{$tab}", $paged );168 // do_action( "install_themes_{$tab}", $paged ); 97 169 ?> 98 170 </div> 171 172 173 <script id="tmpl-theme" type="text/template"> 174 <# if ( data.screenshot_url ) { #> 175 <div class="theme-screenshot"> 176 <img src="{{ data.screenshot_url }}" alt="" /> 177 </div> 178 <# } else { #> 179 <div class="theme-screenshot blank"></div> 180 <# } #> 181 <span class="more-details"><?php _e( 'Theme Details' ); ?></span> 182 <div class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.author }}}' ); ?></div> 183 <h3 class="theme-name">{{{ data.name }}}</h3> 184 185 <div class="theme-actions"> 186 <a class="button button-primary" href="{{{ data.installURI }}}"><?php esc_html_e( 'Install' ); ?></a> 187 <a class="button button-secondary preview install-theme-preview" href=""><?php esc_html_e( 'Preview' ); ?></a> 188 </div> 189 </script> 190 191 <script id="tmpl-theme-single" type="text/template"> 192 <div class="theme-backdrop"></div> 193 <div class="theme-wrap"> 194 <div class="theme-header"> 195 <button alt="<?php _e( 'Show previous theme' ); ?>" class="left dashicons dashicons-no"></button> 196 <button alt="<?php _e( 'Show next theme' ); ?>" class="right dashicons dashicons-no"></button> 197 <button alt="<?php _e( 'Close overlay' ); ?>" class="close dashicons dashicons-no"></button> 198 </div> 199 <div class="theme-about"> 200 <div class="theme-screenshots"> 201 <# if ( data.screenshot_url ) { #> 202 <div class="screenshot"><img src="{{ data.screenshot_url }}" alt="" /></div> 203 <# } else { #> 204 <div class="screenshot blank"></div> 205 <# } #> 206 </div> 207 208 <div class="theme-info"> 209 <h3 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{{ data.version }}}' ); ?></span></h3> 210 <h4 class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.author }}}' ); ?></h4> 211 <p class="theme-description">{{{ data.description }}}</p> 212 213 <div class="rating rating-{{ Math.round( data.rating / 10 ) * 10 }}"> 214 <span class="one"></span> 215 <span class="two"></span> 216 <span class="three"></span> 217 <span class="four"></span> 218 <span class="five"></span> 219 <p class="votes"><?php printf( __( 'Based on %s ratings.' ), '{{{ data.num_ratings }}}' ); ?></p> 220 </div> 221 222 <# if ( data.tags ) { #> 223 <p class="theme-tags"> 224 <span><?php _e( 'Tags:' ); ?></span> 225 <# _.each( data.tags, function( tag ) { #> 226 {{{ tag }}} 227 <# }); #> 228 </p> 229 <# } #> 230 </div> 231 </div> 232 233 <div class="theme-actions"> 234 <a href="{{{ data.installURI }}}" class="button button-primary"><?php _e( 'Install' ); ?></a> 235 <a href="" class="button button-secondary"><?php _e( 'Preview' ); ?></a> 236 <a href="{{{ data.homepage }}}" class="button button-secondary"><?php _e( 'More Info' ); ?></a> 237 </div> 238 </div> 239 </script> 240 241 <script id="tmpl-theme-preview" type="text/template"> 242 <div class="wp-full-overlay-sidebar"> 243 <div class="wp-full-overlay-header"> 244 <a href="" class="close-full-overlay button-secondary"><?php _e( 'Close' ); ?></a> 245 <a href="{{{ data.installURI }}}" class="button button-primary theme-install"><?php _e( 'Install' ); ?></a> 246 </div> 247 <div class="wp-full-overlay-sidebar-content"> 248 <div class="install-theme-info"> 249 <h3 class="theme-name">{{{ data.name }}}</h3> 250 <span class="theme-by"><?php printf( __( 'By %s' ), '{{{ data.author }}}' ); ?></span> 251 252 <img class="theme-screenshot" src="{{ data.screenshot_url }}" alt="" /> 253 254 <div class="theme-details"> 255 <div class="star-rating" title="4.5 rating based on 25 ratings"></div> 256 <div class="theme-version"><?php printf( __( 'Version: %s' ), '{{{ data.version }}}' ); ?></div> 257 <div class="theme-description">{{{ data.description }}}</div> 258 </div> 259 </div> 260 </div> 261 <div class="wp-full-overlay-footer"> 262 <a href="" class="collapse-sidebar" title="<?php esc_attr_e( 'Collapse Sidebar' ); ?>"> 263 <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span> 264 <span class="collapse-sidebar-arrow"></span> 265 </a> 266 </div> 267 </div> 268 <div class="wp-full-overlay-main"> 269 <iframe src="{{{ data.preview_url }}}" /> 270 </div> 271 </script> 272 99 273 <?php 100 274 include(ABSPATH . 'wp-admin/admin-footer.php'); -
src/wp-admin/update.php
diff --git src/wp-admin/update.php src/wp-admin/update.php index d698e26..16145b8 100644
if ( isset($_GET['action']) ) { 202 202 203 203 include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api.. 204 204 205 check_admin_referer( 'install-theme_' . $theme);205 check_admin_referer( 'install-theme' ); 206 206 $api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth. 207 207 208 208 if ( is_wp_error($api) )