Ticket #37974: 37974.3.diff
File 37974.3.diff, 38.7 KB (added by , 8 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
1219 1219 outline: none; 1220 1220 } 1221 1221 1222 .reordering .add-new-item, 1222 1223 .reordering .add-new-widget, 1223 1224 .reordering .add-new-menu-item { 1224 1225 opacity: 0.2; … … 1282 1283 color: #00a0d2; 1283 1284 } 1284 1285 1286 .wp-reorder-nav { 1287 display: none; 1288 background-color: #fff; 1289 position: absolute; 1290 top: 0; 1291 right: 0; 1292 } 1293 1294 .reordering .wp-reorder-nav, 1295 .wp-reorder-nav.is-active { 1296 display: block; 1297 } 1298 1299 .wp-reorder-nav button, 1285 1300 .widget-reorder-nav span, 1286 1301 .menu-item-reorder-nav button { 1287 1302 position: relative; … … 1296 1311 outline: none; 1297 1312 } 1298 1313 1314 .wp-reorder-nav button, 1299 1315 .menu-item-reorder-nav button { 1300 1316 width: 30px; 1301 1317 height: 40px; … … 1305 1321 box-shadow: none; 1306 1322 } 1307 1323 1324 .wp-reorder-nav button:before, 1308 1325 .widget-reorder-nav span:before, 1309 1326 .menu-item-reorder-nav button:before { 1310 1327 display: inline-block; … … 1320 1337 -moz-osx-font-smoothing: grayscale; 1321 1338 } 1322 1339 1340 .wp-reorder-nav button:hover, 1341 .wp-reorder-nav button:focus, 1323 1342 .widget-reorder-nav span:hover, 1324 1343 .widget-reorder-nav span:focus, 1325 1344 .menu-item-reorder-nav button:hover, … … 1328 1347 background: #eee; 1329 1348 } 1330 1349 1350 .wp-reorder-nav button { 1351 width: 33px; 1352 height: 38px; 1353 } 1354 1355 .wp-reorder-nav button:before { 1356 font: normal 20px/38px dashicons; 1357 } 1358 1359 .move-item-down:before, 1331 1360 .move-widget-down:before, 1332 1361 .menus-move-down:before { 1333 1362 content: "\f347"; 1334 1363 } 1335 1364 1365 .move-item-up:before, 1336 1366 .move-widget-up:before, 1337 1367 .menus-move-up:before { 1338 1368 content: "\f343"; … … 1343 1373 .move-up-disabled .menus-move-up, 1344 1374 .move-down-disabled .menus-move-down, 1345 1375 .move-right-disabled .menus-move-right, 1346 .move-left-disabled .menus-move-left { 1376 .move-left-disabled .menus-move-left, 1377 .wp-item:first-child .move-item-up, 1378 .wp-item:last-child .move-item-down { 1347 1379 color: #d5d5d5; 1348 1380 background-color: #fff; 1349 1381 cursor: default; -
src/wp-admin/css/customize-post-collection.css
1 /* General 2 ------------------------------------------------------------------------------*/ 3 4 .customize-dashicon, 5 .drawer-toggle:before { 6 cursor: pointer; 7 display: inline-block; 8 font-family: dashicons; 9 font-size: 20px; 10 -webkit-font-smoothing: antialiased; 11 font-style: normal; 12 font-weight: normal; 13 line-height: 1; 14 position: relative; 15 text-align: center; 16 text-decoration: inherit; 17 vertical-align: top; 18 } 19 20 .drawer-toggle:before { 21 content: "\f132"; 22 position: relative; 23 left: -2px; 24 top: -1px; 25 transition: all 0.2s; 26 vertical-align: middle; 27 } 28 29 .customize-button-delete { 30 color: #a00; 31 } 32 33 .customize-button-delete:hover { 34 color: #f00; 35 } 36 37 .customize-button-delete.customize-dashicon:before { 38 content: "\f335"; 39 } 40 41 .customize-control.is-drawer-open .drawer-toggle:before { 42 transform: rotate( 45deg ); 43 } 44 45 #customize-control-front_page_sections { 46 border-top: 1px solid #ddd; 47 margin-top: 8px; 48 padding-top: 16px; 49 } 50 51 52 /* Drawer 53 ------------------------------------------------------------------------------*/ 54 55 .customize-drawer { 56 background: #eee; 57 border-right: 1px solid #ddd; 58 display: block; 59 margin: 0; 60 overflow-x: hidden; 61 overflow-y: auto; 62 position: absolute; 63 top: 0; 64 right: 0; 65 bottom: 0; 66 left: -301px; 67 transition: left 0.18s; 68 visibility: hidden; 69 width: 300px; 70 z-index: 4; 71 } 72 73 .customize-drawer-notice { 74 padding: 15px; 75 } 76 77 .customize-drawer.is-open { 78 left: 0; 79 visibility: visible; 80 } 81 82 .drawer-is-open .wp-full-overlay-main { 83 left: 300px; 84 } 85 86 87 /* Sortable Item List 88 ------------------------------------------------------------------------------*/ 89 90 .wp-items-list { 91 list-style: none; 92 margin: 0 0 10px 0; 93 padding: 0; 94 position: relative; 95 } 96 97 .wp-item { 98 background: #fff; 99 margin: -1px 0 0 0; 100 padding: 0; 101 } 102 103 .wp-item-header { 104 border: 1px solid #dfdfdf; 105 background: #fff; 106 position: relative; 107 } 108 109 .wp-item-delete { 110 display: none; 111 height: 100%; 112 position: absolute; 113 top: 0; 114 right: 0; 115 bottom: 0; 116 text-align: center; 117 vertical-align: middle; 118 width: 40px; 119 } 120 121 .wp-item-title { 122 cursor: move; 123 margin: 0; 124 padding: 10px 20px; 125 position: relative; 126 word-wrap: break-word; 127 } 128 129 .wp-item.ui-sortable-helper { 130 background: #f9f9f9; 131 border: 1px solid #dfdfdf; 132 } 133 134 .wp-item.ui-sortable-placeholder { 135 background: transparent; 136 border: 1px dashed #a0a5aa; 137 margin-top: 0; 138 margin-bottom: 1px; 139 } 140 141 .wp-item:hover .wp-item-header { 142 border-color: #999; 143 z-index: 1; 144 } 145 146 .customize-control.is-drawer-open .wp-item-delete { 147 display: block; 148 } 149 150 .customize-control.is-drawer-open .wp-reorder-nav { 151 display: none; 152 } 153 154 155 /* Search 156 ------------------------------------------------------------------------------*/ 157 158 .search-group { 159 border-bottom: 1px solid #ddd; 160 margin: 0; 161 padding: 12px 15px; 162 position: relative; 163 } 164 165 .search-group-field { 166 padding: 6px 10px; 167 width: 100%; 168 } 169 170 .search-group-spinner { 171 margin: 0; 172 position: absolute; 173 top: 19px; 174 right: 20px; 175 } 176 177 .search-group-button-clear { 178 background: transparent; 179 border-width: 0; 180 cursor: pointer; 181 display: none; 182 height: 20px; 183 padding: 0; 184 position: absolute; 185 top: 19px; 186 right: 20px; 187 text-align: center; 188 width: 20px; 189 } 190 191 .search-group-button-clear.is-active { 192 display: block; 193 } 194 195 .search-group.is-searching .search-group-button-clear { 196 display: none; 197 } 198 199 200 /* Search Results 201 ------------------------------------------------------------------------------*/ 202 203 .search-results { 204 padding: 1px 0 15px; 205 } 206 207 .search-results ul { 208 margin: -2px 0 0; 209 } 210 211 .search-results-item { 212 background: #fff; 213 border-color: #ddd; 214 border-style: solid; 215 border-width: 1px 0; 216 clear: both; 217 cursor: pointer; 218 line-height: 10px; 219 margin: -1px 0 0 0; 220 padding: 10px 15px; 221 position: relative; 222 } 223 224 .search-results-item-title { 225 display: block; 226 font-size: 13px; 227 font-weight: 600; 228 line-height: 20px; 229 padding-left: 20px; 230 word-wrap: break-word; 231 } 232 233 .search-results-item-type { 234 color: #666; 235 float: right; 236 font-size: 12px; 237 line-height: 20px; 238 text-align: right; 239 } 240 241 .search-results-item-add { 242 color: #82878c; 243 height: 38px; 244 position: absolute; 245 top: 1px; 246 left: 1px; 247 width: 30px; 248 } 249 250 .search-results-item-add:before { 251 -webkit-border-radius: 50%; 252 border-radius: 50%; 253 content: "\f543"; 254 height: 20px; 255 position: relative; 256 top: 0; 257 left: 2px; 258 } 259 260 .search-results-item:hover { 261 border-color: #999; 262 color: #0073aa; 263 z-index: 1; 264 } 265 266 .search-results-item:hover .search-results-item-add:before { 267 color: #0073aa; 268 } 269 270 .search-results-item.is-selected .search-results-item-add:before { 271 content: "\f147"; 272 } -
src/wp-admin/js/customize-post-collection.js
1 (function( wp, $ ) { 2 3 if ( ! wp || ! wp.customize ) { return; } 4 5 var api = wp.customize; 6 7 api.PostCollection = api.PostCollection || {}; 8 9 api.DrawerModel = Backbone.Model.extend({ 10 defaults: { 11 status: 'closed' 12 }, 13 14 close: function() { 15 this.set( 'status', 'closed' ); 16 }, 17 18 open: function() { 19 this.set( 'status', 'open' ); 20 }, 21 22 toggle: function() { 23 if ( 'open' === this.get( 'status' ) ) { 24 this.close(); 25 } else { 26 this.open(); 27 } 28 } 29 }); 30 31 api.DrawerManager = Backbone.Collection.extend({ 32 model: api.DrawerModel, 33 34 initialize: function() { 35 this.on( 'change:status', this.closeOtherDrawers ); 36 }, 37 38 closeOtherDrawers: function( model ) { 39 if ( 'open' === model.get( 'status' ) ) { 40 _.chain( this.models ).without( model ).invoke( 'close' ); 41 } 42 } 43 }); 44 45 api.DrawerView = wp.Backbone.View.extend({ 46 tagName: 'div', 47 className: 'customize-drawer', 48 49 initialize: function( options ) { 50 this.controller = options.controller; 51 this.listenTo( this.controller, 'change:status', this.updateStatusClass ); 52 }, 53 54 updateStatusClass: function() { 55 if ( 'open' === this.controller.get( 'status' ) ) { 56 this.$el.addClass( 'is-open' ); 57 } else { 58 this.$el.removeClass( 'is-open' ); 59 } 60 } 61 }); 62 63 api.PostCollection.PostModel = Backbone.Model.extend({ 64 defaults: { 65 title: '', 66 order: 0 67 } 68 }); 69 70 api.PostCollection.PostsCollection = Backbone.Collection.extend({ 71 model: api.PostCollection.PostModel, 72 73 comparator: function( post ) { 74 return parseInt( post.get( 'order' ), 10 ); 75 } 76 }); 77 78 api.PostCollection.ControlView = wp.Backbone.View.extend({ 79 initialize: function( options ) { 80 this.control = options.control; 81 this.setting = options.setting; 82 83 this.listenTo( this.collection, 'add remove reset sort', this.updateSetting ); 84 this.listenTo( this.control.drawer, 'change:status', this.maybeTriggerSearch ); 85 this.listenTo( this.control.drawer, 'change:status', this.updateStatusClass ); 86 }, 87 88 render: function() { 89 this.views.add([ 90 new api.PostCollection.ItemListView({ 91 collection: this.collection, 92 control: this.control, 93 parent: this 94 }), 95 new api.PostCollection.AddNewItemButtonView({ 96 control: this.control 97 }) 98 ]); 99 100 return this; 101 }, 102 103 maybeTriggerSearch: function() { 104 if ( 'open' === this.control.drawer.get( 'status' ) && this.control.results.length < 1 ) { 105 this.control.search(); 106 } 107 }, 108 109 updateSetting: function() { 110 var postIds = this.collection.sort({ silent: true }).pluck( 'id' ).join( ',' ); 111 this.setting.set( postIds ); 112 }, 113 114 updateStatusClass: function() { 115 if ( 'open' === this.control.drawer.get( 'status' ) ) { 116 this.$el.addClass( 'is-drawer-open' ); 117 } else { 118 this.$el.removeClass( 'is-drawer-open' ); 119 } 120 } 121 }); 122 123 api.PostCollection.AddNewItemButtonView = wp.Backbone.View.extend({ 124 className: 'drawer-toggle add-new-item button button-secondary alignright', 125 tagName: 'button', 126 127 events: { 128 click: 'toggleDrawer' 129 }, 130 131 initialize: function( options ) { 132 this.control = options.control; 133 }, 134 135 render: function() { 136 this.$el.text( this.control.l10n.addPosts ); 137 return this; 138 }, 139 140 toggleDrawer: function( e ) { 141 e.preventDefault(); 142 this.control.drawer.toggle(); 143 } 144 }); 145 146 api.PostCollection.ItemListView = wp.Backbone.View.extend({ 147 className: 'wp-items-list', 148 tagName: 'ol', 149 150 initialize: function( options ) { 151 this.control = options.control; 152 153 this.listenTo( this.collection, 'add', this.addItem ); 154 this.listenTo( this.collection, 'add remove', this.updateOrder ); 155 this.listenTo( this.collection, 'reset', this.render ); 156 }, 157 158 render: function() { 159 this.$el.empty(); 160 this.collection.each( this.addItem, this ); 161 this.initializeSortable(); 162 return this; 163 }, 164 165 initializeSortable: function() { 166 this.$el.sortable({ 167 axis: 'y', 168 delay: 150, 169 forceHelperSize: true, 170 forcePlaceholderSize: true, 171 opacity: 0.6, 172 start: function( e, ui ) { 173 ui.placeholder.css( 'visibility', 'visible' ); 174 }, 175 update: _.bind(function() { 176 this.updateOrder(); 177 }, this ) 178 }); 179 }, 180 181 addItem: function( item ) { 182 var itemView = new api.PostCollection.ItemView({ 183 control: this.control, 184 model: item, 185 parent: this 186 }); 187 188 this.$el.append( itemView.render().el ); 189 }, 190 191 moveDown: function( model ) { 192 var index = this.collection.indexOf( model ), 193 $items = this.$el.children(); 194 195 if ( index < this.collection.length - 1 ) { 196 $items.eq( index ).insertAfter( $items.eq( index + 1 ) ); 197 this.updateOrder(); 198 wp.a11y.speak( this.control.l10n.movedDown ); 199 } 200 }, 201 202 moveUp: function( model ) { 203 var index = this.collection.indexOf( model ), 204 $items = this.$el.children(); 205 206 if ( index > 0 ) { 207 $items.eq( index ).insertBefore( $items.eq( index - 1 ) ); 208 this.updateOrder(); 209 wp.a11y.speak( this.control.l10n.movedUp ); 210 } 211 }, 212 213 updateOrder: function() { 214 _.each( this.$el.find( 'li' ), function( item, i ) { 215 var id = $( item ).data( 'post-id' ); 216 this.collection.get( id ).set( 'order', i ); 217 }, this ); 218 219 this.collection.sort(); 220 } 221 }); 222 223 api.PostCollection.ItemView = wp.Backbone.View.extend({ 224 tagName: 'li', 225 className: 'wp-item', 226 template: wp.template( 'wp-item' ), 227 228 events: { 229 'click .js-remove': 'destroy', 230 'click .move-item-up': 'moveUp', 231 'click .move-item-down': 'moveDown' 232 }, 233 234 initialize: function( options ) { 235 this.control = options.control; 236 this.parent = options.parent; 237 this.listenTo( this.model, 'destroy', this.remove ); 238 }, 239 240 render: function() { 241 var data = _.extend( this.model.toJSON(), { 242 l10n: this.control.l10n 243 }); 244 245 this.$el.html( this.template( data ) ); 246 this.$el.data( 'post-id', this.model.get( 'id' ) ); 247 248 return this; 249 }, 250 251 moveDown: function( e ) { 252 e.preventDefault(); 253 this.parent.moveDown( this.model ); 254 }, 255 256 moveUp: function( e ) { 257 e.preventDefault(); 258 this.parent.moveUp( this.model ); 259 }, 260 261 /** 262 * Destroy the view's model. 263 * 264 * Avoid syncing to the server by triggering an event instead of 265 * calling destroy() directly on the model. 266 */ 267 destroy: function() { 268 this.model.trigger( 'destroy', this.model ); 269 }, 270 271 remove: function() { 272 this.$el.remove(); 273 } 274 }); 275 276 api.PostCollection.DrawerNoticeView = wp.Backbone.View.extend({ 277 tagName: 'div', 278 className: 'customize-drawer-notice', 279 280 initialize: function( options ) { 281 this.control = options.control; 282 this.listenTo( this.control.state, 'change:notice', this.render ); 283 }, 284 285 render: function() { 286 var notice = this.control.state.get( 'notice' ); 287 this.$el.toggle( !! notice.length ).text( notice ); 288 return this; 289 } 290 }); 291 292 api.PostCollection.SearchGroupView = wp.Backbone.View.extend({ 293 tagName: 'div', 294 className: 'search-group', 295 template: wp.template( 'search-group' ), 296 297 events: { 298 'input input': 'search' 299 }, 300 301 initialize: function( options ) { 302 this.control = options.control; 303 }, 304 305 render: function() { 306 this.$el.html( this.template({ l10n: this.control.l10n }) ); 307 this.$field = this.$el.find( '.search-group-field' ); 308 this.$spinner = this.$el.append( '<span class="search-group-spinner spinner" />' ).find( '.spinner' ); 309 310 this.views.add([ 311 new api.PostCollection.ClearResultsButtonView({ 312 collection: this.collection, 313 control: this.control, 314 parent: this 315 }) 316 ]); 317 318 return this; 319 }, 320 321 search: function() { 322 var view = this; 323 324 this.$el.addClass( 'is-searching' ); 325 this.$spinner.addClass( 'is-active' ); 326 327 clearTimeout( this.timeout ); 328 this.timeout = setTimeout(function() { 329 view.control.search( view.$field.val() ) 330 .always(function() { 331 view.$el.removeClass( 'is-searching' ); 332 view.$spinner.removeClass( 'is-active' ); 333 }); 334 }, 300 ); 335 } 336 }); 337 338 api.PostCollection.ClearResultsButtonView = wp.Backbone.View.extend({ 339 tagName: 'button', 340 className: 'search-group-button-clear customize-button-delete customize-dashicon', 341 342 events: { 343 'click': 'clearResults' 344 }, 345 346 initialize: function( options ) { 347 this.control = options.control; 348 this.parent = options.parent; 349 this.listenTo( this.collection, 'add remove reset', this.toggleVisibility ); 350 }, 351 352 render: function() { 353 this.$el.html( $( '<span />', { 354 'class': 'screen-reader-text', 355 text: this.control.l10n.clearResults 356 }) ); 357 this.toggleVisibility(); 358 return this; 359 }, 360 361 clearResults: function() { 362 this.collection.reset(); 363 this.parent.$field.val( '' ); 364 }, 365 366 toggleVisibility: function() { 367 this.$el.toggleClass( 'is-active', !! this.collection.length && '' !== this.parent.$field.val() ); 368 } 369 }); 370 371 api.PostCollection.SearchResultsView = wp.Backbone.View.extend({ 372 tagName: 'div', 373 className: 'search-results', 374 375 initialize: function( options ) { 376 this.control = options.control; 377 this.listenTo( this.collection, 'reset', this.render ); 378 }, 379 380 render: function() { 381 this.$list = this.$el.html( '<ul />' ).find( 'ul' ); 382 383 if ( this.collection.length ) { 384 this.collection.each( this.addItem, this ); 385 } else { 386 this.$el.empty(); 387 } 388 389 return this; 390 }, 391 392 addItem: function( model ) { 393 this.views.add( 'ul', new api.PostCollection.SearchResultView({ 394 control: this.control, 395 model: model 396 })); 397 } 398 }); 399 400 api.PostCollection.SearchResultView = wp.Backbone.View.extend({ 401 tagName: 'li', 402 className: 'search-results-item', 403 template: wp.template( 'search-result' ), 404 405 events: { 406 'click': 'addSection' 407 }, 408 409 initialize: function( options ) { 410 this.control = options.control; 411 this.listenTo( this.control.posts, 'add remove reset', this.updateSelectedClass ); 412 }, 413 414 render: function() { 415 var data = _.extend( this.model.toJSON(), { 416 l10n: this.control.l10n 417 }); 418 419 this.$el.html( this.template( data ) ); 420 this.updateSelectedClass(); 421 422 return this; 423 }, 424 425 addSection: function() { 426 this.control.posts.add( this.model ); 427 }, 428 429 updateSelectedClass: function() { 430 this.$el.toggleClass( 'is-selected', this.control.posts.contains( this.model ) ); 431 } 432 }); 433 434 api.PostCollection.PostCollectionControl = api.Control.extend({ 435 ready: function() { 436 var controlView, drawerView, 437 control = this, 438 section = api.section( this.section() ); 439 440 this.drawer = new api.DrawerModel(); 441 api.drawerManager.add( this.drawer ); 442 443 this.posts = new api.PostCollection.PostsCollection( this.params.posts ); 444 this.results = new api.PostCollection.PostsCollection(); 445 delete this.params.posts; 446 447 this.l10n = this.params.l10n; 448 delete this.params.l10n; 449 450 this.state = new Backbone.Model({ 451 notice: '' 452 }); 453 454 controlView = new api.PostCollection.ControlView({ 455 el: this.container, 456 collection: this.posts, 457 control: this, 458 data: this.params, 459 setting: this.setting 460 }); 461 462 controlView.render(); 463 464 drawerView = new api.DrawerView({ 465 controller: this.drawer 466 }); 467 468 drawerView.views.set([ 469 new api.PostCollection.SearchGroupView({ 470 collection: this.results, 471 control: this 472 }), 473 new api.PostCollection.DrawerNoticeView({ 474 control: this 475 }), 476 new api.PostCollection.SearchResultsView({ 477 collection: this.results, 478 control: this 479 }) 480 ]); 481 482 $( '.wp-full-overlay' ).append( drawerView.render().$el ); 483 484 section.expanded.bind(function( isOpen ) { 485 if ( ! isOpen ) { 486 control.drawer.close(); 487 } 488 }); 489 }, 490 491 search: function( query ) { 492 var control = this; 493 494 return wp.ajax.post( 'customize_find_posts', { 495 s: query, 496 post_types: this.params.postTypes, 497 not_in: this.params.exclude, 498 wp_customize: 'on', 499 _ajax_nonce: this.params.searchNonce 500 }).done(function( response ) { 501 control.results.reset( response ); 502 control.state.set( 'notice', '' ); 503 }).fail(function( response ) { 504 control.results.reset(); 505 control.state.set( 'notice', response ); 506 }); 507 } 508 }); 509 510 /** 511 * Extends wp.customize.controlConstructor with control constructor for 512 * post_collection. 513 */ 514 $.extend( api.controlConstructor, { 515 post_collection: api.PostCollection.PostCollectionControl 516 }); 517 518 /** 519 * Create a global drawer manager. 520 */ 521 api.drawerManager = new api.DrawerManager(); 522 523 /** 524 * Toggle an HTML class on the body when drawers are opened or closed. 525 */ 526 $( document ).ready(function() { 527 var $body = $( document.body ); 528 529 api.drawerManager.on( 'change:status', function() { 530 if ( api.drawerManager.findWhere({ status: 'open' }) ) { 531 $body.addClass( 'drawer-is-open' ); 532 } else { 533 $body.removeClass( 'drawer-is-open' ); 534 } 535 }); 536 }); 537 538 /** 539 * Toggle the front_page_sections control based on the 'show_on_front' 540 * setting value. 541 */ 542 api.bind( 'ready', function() { 543 api( 'show_on_front', function( setting ) { 544 api.control( 'front_page_sections', function( control ) { 545 var toggleVisibility = function( value ) { 546 control.container.toggle( 'page' === value ); 547 }; 548 549 toggleVisibility( setting() ); 550 setting.bind( toggleVisibility ); 551 }); 552 }); 553 }); 554 555 })( window.wp, jQuery ); -
src/wp-includes/canonical.php
655 655 exit; 656 656 } 657 657 } 658 659 /** 660 * Redirect front page section permalinks to the fragment on the front page. 661 * 662 * @since 4.7.0 663 */ 664 function wp_redirect_front_page_sections() { 665 $object_id = get_queried_object_id(); 666 667 if ( 668 ! current_theme_supports( 'front-page-sections' ) 669 || is_front_page() 670 || is_home() 671 || ! is_singular() 672 || ! is_front_page_section( $object_id ) 673 ) { 674 return; 675 } 676 677 wp_redirect( get_front_page_section_url( $object_id ) ); 678 exit; 679 } -
src/wp-includes/class-wp-customize-manager.php
227 227 require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' ); 228 228 require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' ); 229 229 require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-control.php' ); 230 require_once( ABSPATH . WPINC . '/customize/class-wp-customize-post-collection-control.php' ); 230 231 231 232 require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menus-panel.php' ); 232 233 … … 289 290 290 291 add_action( 'wp_ajax_customize_save', array( $this, 'save' ) ); 291 292 add_action( 'wp_ajax_customize_refresh_nonces', array( $this, 'refresh_nonces' ) ); 293 add_action( 'wp_ajax_customize_find_posts', array( $this, 'ajax_find_posts' ) ); 292 294 293 295 add_action( 'customize_register', array( $this, 'register_controls' ) ); 294 296 add_action( 'customize_register', array( $this, 'register_dynamic_settings' ), 11 ); // allow code to create settings first … … 1970 1972 $this->register_control_type( 'WP_Customize_Cropped_Image_Control' ); 1971 1973 $this->register_control_type( 'WP_Customize_Site_Icon_Control' ); 1972 1974 $this->register_control_type( 'WP_Customize_Theme_Control' ); 1975 $this->register_control_type( 'WP_Customize_Post_Collection_Control' ); 1973 1976 1974 1977 /* Themes */ 1975 1978 … … 2302 2305 'section' => 'static_front_page', 2303 2306 'type' => 'dropdown-pages', 2304 2307 ) ); 2308 2309 if ( current_theme_supports( 'front-page-sections' ) ) { 2310 $this->add_setting( 'front_page_sections', array( 2311 'sanitize_callback' => array( $this, 'sanitize_id_list' ), 2312 ) ); 2313 2314 $this->add_control( new WP_Customize_Post_Collection_Control( $this, 'front_page_sections', array( 2315 'label' => __( 'Front page sections' ), 2316 'description' => '', 2317 'section' => 'static_front_page', 2318 'settings' => 'front_page_sections', 2319 'post_types' => get_theme_support( 'front-page-sections', 'post_types' ), 2320 'exclude' => array( 2321 get_option( 'page_on_front' ), 2322 get_option( 'page_for_posts' ), 2323 ), 2324 'l10n' => array( 2325 'addPost' => __( 'Add Section' ), 2326 'addPosts' => __( 'Add Sections' ), 2327 'movedUp' => __( 'Section moved up' ), 2328 'movedDown' => __( 'Section moved down' ), 2329 'removePost' => __( 'Remove Section' ), 2330 'searchPosts' => __( 'Search Sections' ), 2331 'searchPostsPlaceholder' => __( 'Search sections…' ), 2332 ), 2333 ) ) ); 2334 } 2305 2335 } 2306 2336 2307 2337 /** … … 2381 2411 public function _render_custom_logo_partial() { 2382 2412 return get_custom_logo(); 2383 2413 } 2414 2415 /** 2416 * Ajax handler for finding posts. 2417 * 2418 * @since 4.7.0 2419 * 2420 * @see wp_ajax_find_posts() 2421 */ 2422 public function ajax_find_posts() { 2423 check_ajax_referer( 'find-posts' ); 2424 2425 $post_types = array(); 2426 2427 if ( ! empty( $_POST['post_types'] ) ) { 2428 $post_type_names = array_map( 'sanitize_text_field', wp_unslash( $_POST['post_types'] ) ); 2429 foreach ( $post_type_names as $post_type ) { 2430 $post_types[ $post_type ] = get_post_type_object( $post_type ); 2431 } 2432 } 2433 2434 if ( empty( $post_types ) ) { 2435 $post_types['post'] = get_post_type_object( 'post' ); 2436 } 2437 2438 $args = array( 2439 'post_type' => array_keys( $post_types ), 2440 'post_status' => 'publish', 2441 'post__not_in' => isset( $_POST['not_in'] ) ? wp_parse_id_list( $_POST['not_in'] ) : array(), 2442 'posts_per_page' => 50, 2443 ); 2444 2445 if ( ! empty( $_POST['s'] ) ) { 2446 $args['s'] = sanitize_text_field( wp_unslash( $_POST['s'] ) ); 2447 } 2448 2449 $posts = get_posts( $args ); 2450 2451 if ( ! $posts ) { 2452 wp_send_json_error( __( 'No results found.' ) ); 2453 } 2454 2455 foreach ( $posts as $post ) { 2456 $data[] = array( 2457 'id' => $post->ID, 2458 'title' => $post->post_title, 2459 'type' => get_post_type_object( $post->post_type )->labels->singular_name, 2460 ); 2461 } 2462 2463 wp_send_json_success( $data ); 2464 } 2465 2466 /** 2467 * Sanitization callback for lists of IDs. 2468 * 2469 * @since 4.7.0 2470 * 2471 * @param string $value Setting value. 2472 * @return string Comma-separated list of IDs. 2473 */ 2474 public function sanitize_id_list( $value ) { 2475 return implode( ',', array_unique( array_filter( wp_parse_id_list( $value ) ) ) ); 2476 } 2384 2477 } -
src/wp-includes/class-wp-query.php
974 974 $qv['page'] = $qv['paged']; 975 975 unset($qv['paged']); 976 976 } 977 // Add section pages, if they exist. 978 $front_page_sections = array_filter( wp_parse_id_list( get_theme_mod( 'front_page_sections' ) ) ); 979 if ( $front_page_sections ) { 980 array_unshift( $front_page_sections, $qv['page_id'] ); 981 unset( $qv['page_id'] ); 982 983 $qv['post__in'] = $front_page_sections; 984 $qv['orderby'] = 'post__in'; 985 } 977 986 } 978 987 } 979 988 … … 1005 1014 } 1006 1015 } 1007 1016 1008 if ( $qv['page_id']) {1017 if ( ! empty( $qv['page_id'] ) ) { 1009 1018 if ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) { 1010 1019 $this->is_page = false; 1011 1020 $this->is_home = true; -
src/wp-includes/customize/class-wp-customize-post-collection-control.php
1 <?php 2 /** 3 * Customize API: WP_Customize_Post_Collection_Control class 4 * 5 * @package WordPress 6 * @subpackage Customize 7 * @since 4.7.0 8 */ 9 10 /** 11 * Customize Post Collection Control class. 12 * 13 * @since 4.7.0 14 * 15 * @see WP_Customize_Control 16 */ 17 class WP_Customize_Post_Collection_Control extends WP_Customize_Control { 18 /** 19 * Control type. 20 * 21 * @since 4.7.0 22 * @var string 23 */ 24 public $type = 'post_collection'; 25 26 /** 27 * Post types that can be added as sections.. 28 * 29 * @since 4.7.0 30 * @var array 31 */ 32 public $post_types = array( 'page', 'post' ); 33 34 /** 35 * Array of post IDs to exclude from search results. 36 * 37 * @since 4.7.0 38 * @access public 39 * @var array 40 */ 41 public $exclude = array(); 42 43 /** 44 * Localization strings. 45 * 46 * @since 4.7.0 47 * @access public 48 * @var array 49 */ 50 public $l10n = array(); 51 52 /** 53 * Constructor. 54 * 55 * @since 4.7.0 56 * 57 * @param WP_Customize_Manager $manager Customizer bootstrap instance. 58 * @param string $id Control ID. 59 * @param array $args Optional. Arguments to override class property defaults. 60 */ 61 public function __construct( $manager, $id, $args = array() ) { 62 parent::__construct( $manager, $id, $args ); 63 64 $this->l10n = wp_parse_args( $this->l10n, array( 65 'addPost' => __( 'Add Post' ), 66 'addPosts' => __( 'Add Posts' ), 67 'clearResults' => __( 'Clear Results' ), 68 'moveUp' => __( 'Move up' ), 69 'moveDown' => __( 'Move down' ), 70 'movedUp' => __( 'Post moved up' ), 71 'movedDown' => __( 'Post moved down' ), 72 'removePost' => __( 'Remove Post' ), 73 'searchPosts' => __( 'Search Posts' ), 74 'searchPostsPlaceholder' => __( 'Search posts…' ), 75 ) ); 76 } 77 78 /** 79 * Enqueue control related scripts/styles. 80 * 81 * @since 4.7.0 82 */ 83 public function enqueue() { 84 wp_enqueue_style( 'customize-post-collection' ); 85 wp_enqueue_script( 'customize-post-collection' ); 86 87 add_action( 'customize_controls_print_footer_scripts', array( 'WP_Customize_Post_Collection_Control', 'print_templates' ) ); 88 } 89 90 /** 91 * Refresh the parameters passed to the JavaScript via JSON. 92 * 93 * @since 4.7.0 94 * @uses WP_Customize_Control::to_json() 95 */ 96 public function to_json() { 97 parent::to_json(); 98 99 $this->json['exclude'] = $this->exclude; 100 $this->json['l10n'] = $this->l10n; 101 $this->json['posts'] = $this->get_posts(); 102 $this->json['postTypes'] = $this->post_types; 103 $this->json['searchNonce'] = wp_create_nonce( 'find-posts' ); 104 } 105 106 /** 107 * Don't render any content for this control from PHP. 108 * 109 * @since 4.7.0 110 * 111 * @see WP_Customize_Post_Collection_Control::content_template() 112 */ 113 public function render_content() {} 114 115 /** 116 * An Underscore (JS) template for this control's content (but not its container). 117 * 118 * @see WP_Customize_Control::print_template() 119 * 120 * @since 4.7.0 121 */ 122 protected function content_template() { 123 ?> 124 <label> 125 <# if ( data.label ) { #> 126 <span class="customize-control-title">{{ data.label }}</span> 127 <# } #> 128 <# if ( data.description ) { #> 129 <span class="description customize-control-description">{{{ data.description }}}</span> 130 <# } #> 131 </label> 132 <?php 133 } 134 135 /** 136 * Print JavaScript templates in the Customizer footer. 137 * 138 * @since 4.7.0 139 */ 140 public static function print_templates() { 141 ?> 142 <script type="text/html" id="tmpl-wp-item"> 143 <div class="wp-item-header"> 144 <h4 class="wp-item-title">{{ data.title }}</h4> 145 146 <button type="button" class="wp-item-delete customize-button-delete customize-dashicon button-link js-remove"> 147 <span class="screen-reader-text">{{ data.l10n.removePost }}</span> 148 </button> 149 150 <div class="wp-reorder-nav is-active"> 151 <button class="move-item-down" tabindex="0">{{ data.l10n.moveDown }}</button> 152 <button class="move-item-up" tabindex="0">{{ data.l10n.moveUp }}</button> 153 </div> 154 </div> 155 </script> 156 157 <script type="text/html" id="tmpl-search-group"> 158 <label class="screen-reader-text" for="search-group-field">{{ data.l10n.searchPosts }}</label> 159 <input type="text" id="search-group-field" placeholder="{{{ data.l10n.searchPostsPlaceholder }}}" class="search-group-field"> 160 </script> 161 162 <script type="text/html" id="tmpl-search-result"> 163 <span class="search-results-item-type">{{ data.type }}</span> 164 <span class="search-results-item-title">{{ data.title }}</span> 165 166 <button type="button" class="search-results-item-add customize-dashicon button-link"> 167 <span class="screen-reader-text">{{ data.l10n.addPost }}</span> 168 </button> 169 </script> 170 <?php 171 } 172 173 /** 174 * Retrieve posts. 175 * 176 * @since 4.7.0 177 * 178 * @return array 179 */ 180 protected function get_posts() { 181 $data = array(); 182 $value = $this->value(); 183 184 if ( ! empty( $value ) ) { 185 $posts = get_posts( array( 186 'post_type' => $this->post_types, 187 'post_status' => 'any', 188 'post__in' => array_map( 'absint', explode( ',', $value ) ), 189 'orderby' => 'post__in', 190 'posts_per_page' => 20, 191 ) ); 192 } 193 194 if ( ! empty( $posts ) ) { 195 $i = 0; 196 foreach ( $posts as $post ) { 197 $data[] = array( 198 'id' => $post->ID, 199 'title' => $post->post_title, 200 'order' => ++$i, 201 ); 202 } 203 } 204 205 return $data; 206 } 207 } -
src/wp-includes/default-filters.php
427 427 428 428 // Canonical 429 429 add_action( 'template_redirect', 'redirect_canonical' ); 430 add_action( 'template_redirect', 'wp_redirect_front_page_sections' ); 430 431 add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 ); 431 432 432 433 // Shortcodes -
src/wp-includes/link-template.php
312 312 function get_page_link( $post = false, $leavename = false, $sample = false ) { 313 313 $post = get_post( $post ); 314 314 315 if ( 'page' == get_option( 'show_on_front' ) && $post->ID == get_option( 'page_on_front' ) ) 315 if ( 'page' == get_option( 'show_on_front' ) && $post->ID == get_option( 'page_on_front' ) ) { 316 316 $link = home_url('/'); 317 else 317 } elseif ( is_front_page_section( $post->ID ) ) { 318 $link = get_front_page_section_url( $post->ID ); 319 } else { 318 320 $link = _get_page_link( $post, $leavename, $sample ); 321 } 319 322 320 323 /** 321 324 * Filters the permalink for a page. … … 4142 4145 */ 4143 4146 return apply_filters( 'parent_theme_file_path', $path, $file ); 4144 4147 } 4148 4149 /** 4150 * Retrieve the URL for a front page section. 4151 * 4152 * @since 4.7.0 4153 * 4154 * @param int|WP_Post $post Post ID or object. 4155 * @return string 4156 */ 4157 function get_front_page_section_url( $post ) { 4158 return home_url( '#post-' . get_post( $post )->ID ); 4159 } -
src/wp-includes/post-template.php
479 479 $classes[] = 'format-standard'; 480 480 } 481 481 482 // Front page sections. 483 if ( is_front_page() && is_front_page_section( $post->ID ) ) { 484 $classes[] = 'front-page-section'; 485 } 486 482 487 $post_password_required = post_password_required( $post->ID ); 483 488 484 489 // Post requires password. … … 1794 1799 echo $rows; 1795 1800 echo "</ul>"; 1796 1801 } 1802 1803 /** 1804 * Whether a post is a front page section. 1805 * 1806 * @since 4.7.0 1807 * 1808 * @param int $post_id Post ID. 1809 * @return bool 1810 */ 1811 function is_front_page_section( $post_id ) { 1812 $section_ids = array_filter( wp_parse_id_list( get_theme_mod( 'front_page_sections' ) ) ); 1813 return in_array( intval( $post_id ), $section_ids, true ); 1814 } -
src/wp-includes/script-loader.php
476 476 $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 ); 477 477 $scripts->add( 'customize-preview-nav-menus', "/wp-includes/js/customize-preview-nav-menus$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 ); 478 478 479 $scripts->add( 'customize-post-collection', "/wp-admin/js/customize-post-collection$suffix.js", array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-droppable', 'wp-backbone', 'customize-controls' ), false, 1 ); 480 479 481 $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 ); 480 482 481 483 $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 ); … … 819 821 820 822 $styles->add( 'wp-admin', false, array( 'dashicons', 'common', 'forms', 'admin-menu', 'dashboard', 'list-tables', 'edit', 'revisions', 'media', 'themes', 'about', 'nav-menus', 'widgets', 'site-icon', 'l10n' ) ); 821 823 822 $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) ); 823 $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'buttons' ) ); 824 $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" ); 825 $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) ); 826 $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) ); 827 $styles->add( 'customize-nav-menus', "/wp-admin/css/customize-nav-menus$suffix.css", array( 'wp-admin', 'colors' ) ); 828 $styles->add( 'press-this', "/wp-admin/css/press-this$suffix.css", array( 'buttons' ) ); 824 $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) ); 825 $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'buttons' ) ); 826 $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" ); 827 $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) ); 828 $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) ); 829 $styles->add( 'customize-nav-menus', "/wp-admin/css/customize-nav-menus$suffix.css", array( 'wp-admin', 'colors' ) ); 830 $styles->add( 'customize-post-collection', "/wp-admin/css/customize-post-collection$suffix.css", array( 'wp-admin', 'colors', 'customize-controls' ) ); 831 $styles->add( 'press-this', "/wp-admin/css/press-this$suffix.css", array( 'buttons' ) ); 829 832 830 833 $styles->add( 'ie', "/wp-admin/css/ie$suffix.css" ); 831 834 $styles->add_data( 'ie', 'conditional', 'lte IE 7' ); -
src/wp-includes/theme.php
1730 1730 1731 1731 return false; 1732 1732 } 1733 1734 case 'front-page-sections' : 1735 if ( ! is_array( $args ) ) { 1736 $args = array( 0 => array() ); 1737 } 1738 1739 $args[0] = wp_parse_args( $args[0], array( 1740 'post_types' => array( 'page' ), 1741 ) ); 1742 1743 break; 1733 1744 } 1734 1745 1735 1746 $_wp_theme_features[ $feature ] = $args; … … 1822 1833 case 'custom-logo' : 1823 1834 case 'custom-header' : 1824 1835 case 'custom-background' : 1836 case 'front-page-sections' : 1825 1837 if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) ) 1826 1838 return $_wp_theme_features[ $feature ][0][ $args[0] ]; 1827 1839 return false; … … 2082 2094 return; 2083 2095 } 2084 2096 2085 require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; 2097 require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; 2086 2098 $GLOBALS['wp_customize'] = new WP_Customize_Manager(); 2087 2099 } 2088 2100