Make WordPress Core

Ticket #37974: 37974.7.diff

File 37974.7.diff, 43.5 KB (added by pento, 8 years ago)
  • src/wp-admin/css/customize-controls.css

     
    687687
    688688/* Style for custom settings */
    689689
     690#customize-control-front_page_sections {
     691        border-top: 1px solid #ddd;
     692        margin-top: 8px;
     693        padding-top: 16px;
     694}
     695
    690696/**
    691697 * Dropdowns
    692698 */
     
    12051211 */
    12061212
    12071213/* higher specificity than .wp-core-ui .button */
     1214#customize-theme-controls .add-new-item,
    12081215#customize-theme-controls .add-new-widget,
    12091216#customize-theme-controls .add-new-menu-item {
    12101217        cursor: pointer;
     
    12191226        outline: none;
    12201227}
    12211228
     1229.reordering .add-new-item,
    12221230.reordering .add-new-widget,
    12231231.reordering .add-new-menu-item {
    12241232        opacity: 0.2;
     
    12261234        cursor: not-allowed; /* doesn't work in conjunction with pointer-events */
    12271235}
    12281236
     1237.add-new-item:before,
    12291238.add-new-widget:before,
    12301239.add-new-menu-item:before,
    12311240#available-menu-items .new-content-item .add-content:before {
     
    12821291        color: #00a0d2;
    12831292}
    12841293
     1294.wp-reorder-nav {
     1295        display: none;
     1296        background-color: #fff;
     1297        position: absolute;
     1298        top: 0;
     1299        right: 0;
     1300}
     1301
     1302.reordering .wp-reorder-nav,
     1303.wp-reorder-nav.is-active {
     1304        display: block;
     1305}
     1306
     1307.wp-reorder-nav button,
    12851308.widget-reorder-nav span,
    12861309.menu-item-reorder-nav button {
    12871310        position: relative;
     
    12961319        outline: none;
    12971320}
    12981321
     1322.wp-reorder-nav button,
    12991323.menu-item-reorder-nav button {
    13001324        width: 30px;
    13011325        height: 40px;
     
    13051329        box-shadow: none;
    13061330}
    13071331
     1332.wp-reorder-nav button:before,
    13081333.widget-reorder-nav span:before,
    13091334.menu-item-reorder-nav button:before {
    13101335        display: inline-block;
     
    13201345        -moz-osx-font-smoothing: grayscale;
    13211346}
    13221347
     1348.wp-reorder-nav button:hover,
     1349.wp-reorder-nav button:focus,
    13231350.widget-reorder-nav span:hover,
    13241351.widget-reorder-nav span:focus,
    13251352.menu-item-reorder-nav button:hover,
     
    13281355        background: #eee;
    13291356}
    13301357
     1358.wp-reorder-nav button {
     1359        width: 33px;
     1360        height: 38px;
     1361}
     1362
     1363.wp-reorder-nav button:before {
     1364        font: normal 20px/38px dashicons;
     1365}
     1366
     1367.move-item-down:before,
    13311368.move-widget-down:before,
    13321369.menus-move-down:before {
    13331370        content: "\f347";
    13341371}
    13351372
     1373.move-item-up:before,
    13361374.move-widget-up:before,
    13371375.menus-move-up:before {
    13381376        content: "\f343";
     
    13431381.move-up-disabled .menus-move-up,
    13441382.move-down-disabled .menus-move-down,
    13451383.move-right-disabled .menus-move-right,
    1346 .move-left-disabled .menus-move-left {
     1384.move-left-disabled .menus-move-left,
     1385.wp-item:first-child .move-item-up,
     1386.wp-item:last-child .move-item-down {
    13471387        color: #d5d5d5;
    13481388        background-color: #fff;
    13491389        cursor: default;
     
    13511391}
    13521392
    13531393/**
    1354  * New widget and Add-menu-items modes and panels
     1394 * New widget, Add-menu-items, and Drawer modes and panels
    13551395 */
    13561396
    13571397.wp-full-overlay-main {
     
    13591399        width: 100%;
    13601400}
    13611401
     1402.customize-control.is-drawer-open .add-new-item,
     1403.customize-control.is-drawer-open .add-new-item:hover,
    13621404body.adding-widget .add-new-widget,
    13631405body.adding-widget .add-new-widget:hover,
    13641406.adding-menu-items .add-new-menu-item,
     
    13721414        box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
    13731415}
    13741416
     1417.customize-control.is-drawer-open .add-new-item:before,
    13751418body.adding-widget .add-new-widget:before,
    13761419.adding-menu-items .add-new-menu-item:before,
    13771420#accordion-section-add_menu .add-new-menu-item.open:before {
     
    13801423        transform: rotate(45deg);
    13811424}
    13821425
     1426.customize-drawer,
    13831427#available-widgets,
    13841428#available-menu-items {
    13851429        position: absolute;
     
    13981442        border-right: 1px solid #ddd;
    13991443}
    14001444
     1445.customize-drawer .customize-section-title,
    14011446#available-widgets .customize-section-title,
    14021447#available-menu-items .customize-section-title {
    14031448        display: none;
     
    14251470}
    14261471
    14271472/* search field container */
     1473.search-group,
    14281474#available-widgets-filter,
    14291475#available-menu-items-search .accordion-section-title {
    14301476        padding: 13px 15px;
     
    14331479        box-sizing: border-box;
    14341480}
    14351481
     1482.search-group {
     1483        position: relative;
     1484}
     1485
     1486.search-group input,
    14361487#available-widgets-filter input,
    14371488#available-menu-items-search input {
    14381489        width: 100%;
     
    14411492        padding: 6px 30px;
    14421493}
    14431494
     1495.search-group input::-ms-clear,
    14441496#available-widgets-filter input::-ms-clear,
    14451497#available-menu-items-search input::-ms-clear {
    14461498        display: none; /* remove the "x" in IE, which conflicts with the "x" icon on button.clear-results */
    14471499}
    14481500
     1501.search-group .search-icon,
    14491502#available-menu-items-search .search-icon,
    14501503#available-widgets-filter .search-icon {
    14511504        display: block;
     
    14591512        color: #72777c;
    14601513}
    14611514
     1515.search-group .clear-results,
    14621516#available-widgets-filter .clear-results,
    14631517#available-menu-items-search .clear-results {
    14641518        position: absolute;
     
    14751529        outline: 0;
    14761530}
    14771531
     1532.search-group .clear-results,
    14781533#available-widgets-filter .clear-results,
    14791534#available-menu-items-search .clear-results,
    14801535#available-menu-items-search.loading .clear-results.is-visible {
    14811536        display: none;
    14821537}
    14831538
     1539.search-group .clear-results.is-visible,
    14841540#available-widgets-filter .clear-results.is-visible,
    14851541#available-menu-items-search .clear-results.is-visible {
    14861542        display: block;
    14871543}
    14881544
     1545.search-group .clear-results:before,
    14891546#available-widgets-filter .clear-results:before,
    14901547#available-menu-items-search .clear-results:before {
    14911548        content: "\f335";
     
    14951552        -moz-osx-font-smoothing: grayscale;
    14961553}
    14971554
     1555.search-group .clear-results:hover,
     1556.search-group .clear-results:focus,
    14981557#available-widgets-filter .clear-results:hover,
    14991558#available-widgets-filter .clear-results:focus,
    15001559#available-menu-items-search .clear-results:hover,
     
    15021561        color: #dc3232;
    15031562}
    15041563
     1564.search-group .clear-results:focus,
    15051565#available-widgets-filter .clear-results:focus,
    15061566#available-menu-items-search .clear-results:focus {
    15071567        -webkit-box-shadow:
     
    15121572                0 0 2px 1px rgba(30, 140, 190, .8);
    15131573}
    15141574
     1575.search-group .search-icon:after,
    15151576#available-menu-items-search .search-icon:after,
    15161577#available-widgets-filter .search-icon:after {
    15171578        content: "\f179";
     
    15211582        -moz-osx-font-smoothing: grayscale;
    15221583}
    15231584
     1585.search-group .spinner {
     1586        margin: 0;
     1587        position: absolute;
     1588        top: 20px;
     1589        right: 20px;
     1590}
     1591
     1592.search-group.is-searching .clear-results {
     1593        display: none;
     1594}
     1595
    15241596.no-widgets-found-message {
    15251597        display: none;
    15261598        margin: 0;
     
    15581630        position: static;
    15591631}
    15601632
     1633.customize-drawer.is-open {
     1634        left: 0;
     1635        visibility: visible;
     1636}
     1637
     1638body.drawer-is-open .wp-full-overlay-main {
     1639        left: 300px;
     1640}
     1641
     1642body.drawer-is-open #customize-preview {
     1643        opacity: 0.4;
     1644}
     1645
     1646.ios .customize-drawer {
     1647        -webkit-transition: left 0s;
     1648        transition: left 0s;
     1649}
     1650
     1651.customize-drawer-notice {
     1652        padding: 15px;
     1653}
     1654
     1655/* Sortable list items. */
     1656
     1657.wp-items-list {
     1658        list-style: none;
     1659        margin: 0 0 10px 0;
     1660        padding: 0;
     1661        position: relative;
     1662}
     1663
     1664.wp-item {
     1665        background: #fff;
     1666        margin: -1px 0 0 0;
     1667        padding: 0;
     1668}
     1669
     1670.wp-item-header {
     1671        border: 1px solid #dfdfdf;
     1672        background: #fff;
     1673        position: relative;
     1674}
     1675
     1676.wp-item-delete {
     1677        color: #a00;
     1678        height: 38px;
     1679        position: absolute;
     1680        top: 0;
     1681        right: 0;
     1682        text-align: center;
     1683        vertical-align: middle;
     1684        width: 33px;
     1685}
     1686
     1687.wp-item-delete:hover {
     1688        color: #f00;
     1689}
     1690
     1691.wp-item-delete:before {
     1692        content: "\f335";
     1693}
     1694
     1695.wp-item-title {
     1696        cursor: move;
     1697        margin: 0;
     1698        padding: 10px 20px;
     1699        position: relative;
     1700        word-wrap: break-word;
     1701}
     1702
     1703/* Corner knockout to account for controls */
     1704.wp-item-title:before {
     1705        content: "";
     1706        float: right;
     1707        height: 28px;
     1708        width: 79px; /* wp-reorder-nav width (66) plus delete button width (33) */
     1709}
     1710
     1711.wp-item .wp-reorder-nav {
     1712        right: 33px;
     1713}
     1714
     1715.wp-item.ui-sortable-helper {
     1716        background: #f9f9f9;
     1717        border: 1px solid #dfdfdf;
     1718}
     1719
     1720.wp-item.ui-sortable-placeholder {
     1721        background: transparent;
     1722        border: 1px dashed #a0a5aa;
     1723        margin-top: 0;
     1724        margin-bottom: 1px;
     1725}
     1726
     1727.wp-item:hover .wp-item-header {
     1728        border-color: #999;
     1729        z-index: 1;
     1730}
     1731
     1732/* Search results. */
     1733
     1734.search-results {
     1735        padding: 1px 0 15px;
     1736}
     1737
     1738.search-results ul {
     1739        margin: -1px 0 0;
     1740}
     1741
     1742.search-results-item {
     1743        background: #fff;
     1744        border-color: #ddd;
     1745        border-style: solid;
     1746        border-width: 1px 0;
     1747        clear: both;
     1748        cursor: pointer;
     1749        line-height: 10px;
     1750        margin: -1px 0 0 0;
     1751        padding: 10px 15px;
     1752        position: relative;
     1753}
     1754
     1755.search-results-item-title {
     1756        display: block;
     1757        font-size: 13px;
     1758        font-weight: 600;
     1759        line-height: 20px;
     1760        padding-left: 20px;
     1761        word-wrap: break-word;
     1762}
     1763
     1764.search-results-item-type {
     1765        color: #666;
     1766        float: right;
     1767        font-size: 12px;
     1768        line-height: 20px;
     1769        padding-left: 10px;
     1770        text-align: right;
     1771}
     1772
     1773.search-results-item-add {
     1774        color: #82878c;
     1775        height: 38px;
     1776        position: absolute;
     1777        top: 1px;
     1778        left: 1px;
     1779        width: 30px;
     1780}
     1781
     1782.search-results-item-add:before {
     1783        -webkit-border-radius: 50%;
     1784        border-radius: 50%;
     1785        content: "\f543";
     1786        height: 20px;
     1787        position: relative;
     1788        top: 0;
     1789        left: 2px;
     1790}
     1791
     1792.search-results-item:hover {
     1793        border-color: #999;
     1794        color: #0073aa;
     1795        z-index: 1;
     1796}
     1797
     1798.search-results-item:hover .search-results-item-add:before {
     1799        color: #0073aa;
     1800}
     1801
     1802.search-results-item.is-selected .search-results-item-add:before {
     1803        content: "\f147";
     1804}
     1805
     1806.search-results-item-add,
     1807.wp-item-delete {
     1808        cursor: pointer;
     1809        display: inline-block;
     1810        font-family: dashicons;
     1811        font-size: 20px;
     1812        -webkit-font-smoothing: antialiased;
     1813        font-style: normal;
     1814        font-weight: normal;
     1815        line-height: 1;
     1816        text-align: center;
     1817        text-decoration: inherit;
     1818        vertical-align: top;
     1819}
     1820
     1821.search-results.hide-type-label .search-results-item-type {
     1822        display: none;
     1823}
     1824
    15611825
    15621826/* Responsive */
    15631827.customize-controls-preview-toggle {
     
    16791943                margin-top: 6px;
    16801944        }
    16811945
     1946        body.drawer-is-open .customize-drawer,
    16821947        body.adding-widget div#available-widgets,
    16831948        body.adding-menu-items div#available-menu-items {
    16841949                top: 46px;
     
    16871952                width: 100%;
    16881953        }
    16891954
     1955        .customize-drawer .customize-section-title,
    16901956        #available-widgets .customize-section-title,
    16911957        #available-menu-items .customize-section-title {
    16921958                display: block;
    16931959                margin: 0;
    16941960        }
    16951961
     1962        .customize-drawer .customize-section-back,
    16961963        #available-widgets .customize-section-back,
    16971964        #available-menu-items .customize-section-back {
    16981965                height: 69px;
    16991966        }
    17001967
     1968        .customize-drawer .customize-section-title h3,
    17011969        #available-widgets .customize-section-title h3,
    17021970        #available-menu-items .customize-section-title h3 {
    17031971                font-size: 20px;
     
    17121980                text-overflow: ellipsis;
    17131981        }
    17141982
     1983        .customize-drawer .customize-section-title .customize-action,
    17151984        #available-widgets .customize-section-title .customize-action,
    17161985        #available-menu-items .customize-section-title .customize-action {
    17171986                font-size: 13px;
  • 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.CustomizeSectionTitleView = wp.Backbone.View.extend({
     64                className: 'customize-section-title',
     65                template: wp.template( 'customize-section-title' ),
     66
     67                events: {
     68                        'click .customize-section-back': 'closeDrawer'
     69                },
     70
     71                initialize: function( options ) {
     72                        this.control = options.control;
     73                },
     74
     75                render: function() {
     76                        var data = {
     77                                        label: this.control.params.label,
     78                                        l10n: this.control.l10n
     79                                };
     80
     81                        this.$el.html( this.template( data ) );
     82
     83                        return this;
     84                },
     85
     86                closeDrawer: function( e ) {
     87                        e.preventDefault();
     88                        this.control.drawer.close();
     89                }
     90        });
     91
     92        api.PostCollection.PostModel = Backbone.Model.extend({
     93                defaults: {
     94                        title: '',
     95                        order: 0
     96                }
     97        });
     98
     99        api.PostCollection.PostsCollection = Backbone.Collection.extend({
     100                model: api.PostCollection.PostModel,
     101
     102                comparator: function( post ) {
     103                        return parseInt( post.get( 'order' ), 10 );
     104                }
     105        });
     106
     107        api.PostCollection.ControlView = wp.Backbone.View.extend({
     108                initialize: function( options ) {
     109                        this.control = options.control;
     110                        this.setting = options.setting;
     111
     112                        this.listenTo( this.collection, 'add remove reset sort', this.updateSetting );
     113                        this.listenTo( this.control.drawer, 'change:status', this.maybeTriggerSearch );
     114                        this.listenTo( this.control.drawer, 'change:status', this.updateStatusClass );
     115                },
     116
     117                render: function() {
     118                        this.views.add([
     119                                new api.PostCollection.ItemListView({
     120                                        collection: this.collection,
     121                                        control: this.control,
     122                                        parent: this
     123                                }),
     124                                new api.PostCollection.AddNewItemButtonView({
     125                                        control: this.control
     126                                })
     127                        ]);
     128
     129                        return this;
     130                },
     131
     132                maybeTriggerSearch: function() {
     133                        if ( 'open' === this.control.drawer.get( 'status' ) && this.control.results.length < 1 ) {
     134                                this.control.search();
     135                        }
     136                },
     137
     138                updateSetting: function() {
     139                        var postIds = this.collection.sort({ silent: true }).pluck( 'id' ).join( ',' );
     140                        this.setting.set( postIds );
     141                },
     142
     143                updateStatusClass: function() {
     144                        if ( 'open' === this.control.drawer.get( 'status' ) ) {
     145                                this.$el.addClass( 'is-drawer-open' );
     146                        } else {
     147                                this.$el.removeClass( 'is-drawer-open' );
     148                        }
     149                }
     150        });
     151
     152        api.PostCollection.AddNewItemButtonView = wp.Backbone.View.extend({
     153                className: 'add-new-item button button-secondary alignright',
     154                tagName: 'button',
     155
     156                events: {
     157                        click: 'toggleDrawer'
     158                },
     159
     160                initialize: function( options ) {
     161                        this.control = options.control;
     162                },
     163
     164                render: function() {
     165                        this.$el.text( this.control.l10n.addPosts );
     166                        return this;
     167                },
     168
     169                toggleDrawer: function( e ) {
     170                        e.preventDefault();
     171                        this.control.drawer.toggle();
     172                }
     173        });
     174
     175        api.PostCollection.ItemListView = wp.Backbone.View.extend({
     176                className: 'wp-items-list',
     177                tagName: 'ol',
     178
     179                initialize: function( options ) {
     180                        this.control = options.control;
     181
     182                        this.listenTo( this.collection, 'add', this.addItem );
     183                        this.listenTo( this.collection, 'add remove', this.updateOrder );
     184                        this.listenTo( this.collection, 'reset', this.render );
     185                },
     186
     187                render: function() {
     188                        this.$el.empty();
     189                        this.collection.each( this.addItem, this );
     190                        this.initializeSortable();
     191                        return this;
     192                },
     193
     194                initializeSortable: function() {
     195                        this.$el.sortable({
     196                                axis: 'y',
     197                                delay: 150,
     198                                forceHelperSize: true,
     199                                forcePlaceholderSize: true,
     200                                opacity: 0.6,
     201                                start: function( e, ui ) {
     202                                        ui.placeholder.css( 'visibility', 'visible' );
     203                                },
     204                                update: _.bind(function() {
     205                                        this.updateOrder();
     206                                }, this )
     207                        });
     208                },
     209
     210                addItem: function( item ) {
     211                        var itemView = new api.PostCollection.ItemView({
     212                                control: this.control,
     213                                model: item,
     214                                parent: this
     215                        });
     216
     217                        this.$el.append( itemView.render().el );
     218                },
     219
     220                moveDown: function( model ) {
     221                        var index = this.collection.indexOf( model ),
     222                                $items = this.$el.children();
     223
     224                        if ( index < this.collection.length - 1 ) {
     225                                $items.eq( index ).insertAfter( $items.eq( index + 1 ) );
     226                                this.updateOrder();
     227                                wp.a11y.speak( this.control.l10n.movedDown );
     228                        }
     229                },
     230
     231                moveUp: function( model ) {
     232                        var index = this.collection.indexOf( model ),
     233                                $items = this.$el.children();
     234
     235                        if ( index > 0 ) {
     236                                $items.eq( index ).insertBefore( $items.eq( index - 1 ) );
     237                                this.updateOrder();
     238                                wp.a11y.speak( this.control.l10n.movedUp );
     239                        }
     240                },
     241
     242                updateOrder: function() {
     243                        _.each( this.$el.find( 'li' ), function( item, i ) {
     244                                var id = $( item ).data( 'post-id' );
     245                                this.collection.get( id ).set( 'order', i );
     246                        }, this );
     247
     248                        this.collection.sort();
     249                }
     250        });
     251
     252        api.PostCollection.ItemView = wp.Backbone.View.extend({
     253                tagName: 'li',
     254                className: 'wp-item',
     255                template: wp.template( 'wp-item' ),
     256
     257                events: {
     258                        'click .js-remove': 'destroy',
     259                        'click .move-item-up': 'moveUp',
     260                        'click .move-item-down': 'moveDown'
     261                },
     262
     263                initialize: function( options ) {
     264                        this.control = options.control;
     265                        this.parent = options.parent;
     266                        this.listenTo( this.model, 'destroy', this.remove );
     267                },
     268
     269                render: function() {
     270                        var data = _.extend( this.model.toJSON(), {
     271                                l10n: this.control.l10n,
     272                                includeFrontPage: this.control.params.includeFrontPage,
     273                        });
     274
     275                        this.$el.html( this.template( data ) );
     276                        this.$el.data( 'post-id', this.model.get( 'id' ) );
     277
     278                        return this;
     279                },
     280
     281                moveDown: function( e ) {
     282                        e.preventDefault();
     283                        this.parent.moveDown( this.model );
     284                },
     285
     286                moveUp: function( e ) {
     287                        e.preventDefault();
     288                        this.parent.moveUp( this.model );
     289                },
     290
     291                /**
     292                 * Destroy the view's model.
     293                 *
     294                 * Avoid syncing to the server by triggering an event instead of
     295                 * calling destroy() directly on the model.
     296                 */
     297                destroy: function() {
     298                        this.model.trigger( 'destroy', this.model );
     299                },
     300
     301                remove: function() {
     302                        this.$el.remove();
     303                }
     304        });
     305
     306        api.PostCollection.DrawerNoticeView = wp.Backbone.View.extend({
     307                tagName: 'div',
     308                className: 'customize-drawer-notice',
     309
     310                initialize: function( options ) {
     311                        this.control = options.control;
     312                        this.listenTo( this.control.state, 'change:notice', this.render );
     313                },
     314
     315                render: function() {
     316                        var notice = this.control.state.get( 'notice' );
     317                        this.$el.toggle( !! notice.length ).text( notice );
     318                        return this;
     319                }
     320        });
     321
     322        api.PostCollection.SearchGroupView = wp.Backbone.View.extend({
     323                tagName: 'div',
     324                className: 'search-group',
     325                template: wp.template( 'search-group' ),
     326
     327                events: {
     328                        'click .clear-results' : 'clearResults',
     329                        'input input': 'search'
     330                },
     331
     332                initialize: function( options ) {
     333                        this.control = options.control;
     334                        this.listenTo( this.collection, 'add remove reset', this.updateClearResultsVisibility );
     335                },
     336
     337                render: function() {
     338                        this.$el.html( this.template({ l10n: this.control.l10n }) );
     339                        this.$clearResults = this.$( '.clear-results' );
     340                        this.$field = this.$( '.search-group-field' );
     341                        this.$spinner = this.$el.append( '<span class="search-group-spinner spinner" />' ).find( '.spinner' );
     342                        this.updateClearResultsVisibility();
     343                        return this;
     344                },
     345
     346                clearResults: function() {
     347                        this.collection.reset();
     348                        this.$field.val( '' ).trigger( 'input' ).focus();
     349                },
     350
     351                search: function() {
     352                        var view = this;
     353
     354                        this.$el.addClass( 'is-searching' );
     355                        this.$spinner.addClass( 'is-active' );
     356
     357                        clearTimeout( this.timeout );
     358                        this.timeout = setTimeout(function() {
     359                                view.control.search( view.$field.val() )
     360                                        .always(function() {
     361                                                view.$el.removeClass( 'is-searching' );
     362                                                view.$spinner.removeClass( 'is-active' );
     363                                        });
     364                        }, 300 );
     365                },
     366
     367                updateClearResultsVisibility: function() {
     368                        this.$clearResults.toggleClass( 'is-visible', !! this.collection.length && '' !== this.$field.val() );
     369                }
     370        });
     371
     372        api.PostCollection.SearchResultsView = wp.Backbone.View.extend({
     373                tagName: 'div',
     374                className: 'search-results',
     375
     376                initialize: function( options ) {
     377                        this.control = options.control;
     378                        this.listenTo( this.collection, 'reset', this.render );
     379                },
     380
     381                render: function() {
     382                        this.$list = this.$el.html( '<ul />' ).find( 'ul' );
     383                        this.$el.toggleClass( 'hide-type-label', 1 === this.control.params.postTypes.length );
     384
     385                        if ( this.collection.length ) {
     386                                this.collection.each( this.addItem, this );
     387                        } else {
     388                                this.$el.empty();
     389                        }
     390
     391                        return this;
     392                },
     393
     394                addItem: function( model ) {
     395                        this.views.add( 'ul', new api.PostCollection.SearchResultView({
     396                                control: this.control,
     397                                model: model
     398                        }));
     399                }
     400        });
     401
     402        api.PostCollection.SearchResultView = wp.Backbone.View.extend({
     403                tagName: 'li',
     404                className: 'search-results-item',
     405                template: wp.template( 'search-result' ),
     406
     407                events: {
     408                        'click': 'addItem'
     409                },
     410
     411                initialize: function( options ) {
     412                        this.control = options.control;
     413                        this.listenTo( this.control.posts, 'add remove reset', this.updateSelectedClass );
     414                },
     415
     416                render: function() {
     417                        var data = _.extend( this.model.toJSON(), {
     418                                l10n: this.control.l10n
     419                        });
     420
     421                        this.$el.html( this.template( data ) );
     422                        this.updateSelectedClass();
     423
     424                        return this;
     425                },
     426
     427                addItem: function() {
     428                        this.control.posts.add( this.model );
     429                },
     430
     431                updateSelectedClass: function() {
     432                        this.$el.toggleClass( 'is-selected', !! this.control.posts.findWhere({ id: this.model.get( 'id' ) }) );
     433                }
     434        });
     435
     436        api.PostCollection.PostCollectionControl = api.Control.extend({
     437                ready: function() {
     438                        var controlView, drawerView,
     439                                control = this,
     440                                section = api.section( this.section() );
     441
     442                        this.drawer = new api.DrawerModel();
     443                        api.drawerManager.add( this.drawer );
     444
     445                        this.posts = new api.PostCollection.PostsCollection( this.params.posts );
     446                        this.results = new api.PostCollection.PostsCollection();
     447                        delete this.params.posts;
     448
     449                        this.l10n = this.params.l10n;
     450                        delete this.params.l10n;
     451
     452                        this.state = new Backbone.Model({
     453                                notice: ''
     454                        });
     455
     456                        controlView = new api.PostCollection.ControlView({
     457                                el: this.container,
     458                                collection: this.posts,
     459                                control: this,
     460                                data: this.params,
     461                                setting: this.setting
     462                        });
     463
     464                        controlView.render();
     465
     466                        drawerView = new api.DrawerView({
     467                                controller: this.drawer
     468                        });
     469
     470                        drawerView.views.set([
     471                                new api.PostCollection.CustomizeSectionTitleView({
     472                                        control: this
     473                                }),
     474                                new api.PostCollection.SearchGroupView({
     475                                        collection: this.results,
     476                                        control: this
     477                                }),
     478                                new api.PostCollection.DrawerNoticeView({
     479                                        control: this
     480                                }),
     481                                new api.PostCollection.SearchResultsView({
     482                                        collection: this.results,
     483                                        control: this
     484                                })
     485                        ]);
     486
     487                        $( '.wp-full-overlay' ).append( drawerView.render().$el );
     488
     489                        section.expanded.bind(function( isOpen ) {
     490                                if ( ! isOpen ) {
     491                                        control.drawer.close();
     492                                }
     493                        });
     494                },
     495
     496                search: function( query ) {
     497                        var args = {},
     498                                control = this;
     499
     500                        args = {
     501                                s: query,
     502                                post_types: this.params.postTypes,
     503                                not_in: [],
     504                                wp_customize: 'on',
     505                                _ajax_nonce: this.params.searchNonce
     506                        };
     507
     508                        if ( 'front_page_sections' === this.setting.id ) {
     509                                args.not_in.push( api( 'page_on_front' )() );
     510                        }
     511
     512                        return wp.ajax.post( 'customize_find_posts', args )
     513                                .done(function( response ) {
     514                                        control.results.reset( response );
     515                                        control.state.set( 'notice', '' );
     516                                })
     517                                .fail(function( response ) {
     518                                        control.results.reset();
     519                                        control.state.set( 'notice', response );
     520                                });
     521                }
     522        });
     523
     524        /**
     525         * Extends wp.customize.controlConstructor with control constructor for
     526         * post_collection.
     527         */
     528        $.extend( api.controlConstructor, {
     529                post_collection: api.PostCollection.PostCollectionControl
     530        });
     531
     532        /**
     533         * Create a global drawer manager.
     534         */
     535        api.drawerManager = new api.DrawerManager();
     536
     537        /**
     538         * Toggle an HTML class on the body when drawers are opened or closed.
     539         */
     540        $( document ).ready(function() {
     541                var $body = $( document.body );
     542
     543                api.drawerManager.on( 'change:status', function() {
     544                        if ( api.drawerManager.findWhere({ status: 'open' }) ) {
     545                                $body.addClass( 'drawer-is-open' );
     546                        } else {
     547                                $body.removeClass( 'drawer-is-open' );
     548                        }
     549                });
     550        });
     551
     552        /**
     553         * Toggle the front_page_sections control based on the 'show_on_front'
     554         * setting value.
     555         */
     556        api.bind( 'ready', function() {
     557                api( 'show_on_front', function( setting ) {
     558                        api.control( 'front_page_sections', function( control ) {
     559                                var toggleVisibility = function( value ) {
     560                                        control.container.toggle( 'page' === value );
     561                                };
     562
     563                                toggleVisibility( setting() );
     564                                setting.bind( toggleVisibility );
     565                        });
     566                });
     567        });
     568
     569})( window.wp, jQuery );
  • src/wp-includes/canonical.php

    Property changes on: src/wp-admin/js/customize-post-collection.js
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    655655                exit;
    656656        }
    657657}
     658
     659/**
     660 * Redirect front page section permalinks to the fragment on the front page.
     661 *
     662 * @since 4.7.0
     663 */
     664function wp_redirect_front_page_sections() {
     665        $object_id = get_queried_object_id();
     666        return;
     667
     668        if (
     669                ! current_theme_supports( 'front-page-sections' )
     670                || is_front_page()
     671                || is_home()
     672                || ! is_singular()
     673                || ! is_front_page_section( $object_id )
     674        ) {
     675                return;
     676        }
     677
     678        wp_redirect( get_front_page_section_url( $object_id ) );
     679        exit;
     680}
  • src/wp-includes/class-wp-customize-manager.php

     
    227227                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' );
    228228                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' );
    229229                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' );
    230231
    231232                require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menus-panel.php' );
    232233
     
    289290
    290291                add_action( 'wp_ajax_customize_save',           array( $this, 'save' ) );
    291292                add_action( 'wp_ajax_customize_refresh_nonces', array( $this, 'refresh_nonces' ) );
     293                add_action( 'wp_ajax_customize_find_posts',     array( $this, 'ajax_find_posts' ) );
    292294
    293295                add_action( 'customize_register',                 array( $this, 'register_controls' ) );
    294296                add_action( 'customize_register',                 array( $this, 'register_dynamic_settings' ), 11 ); // allow code to create settings first
     
    19701972                $this->register_control_type( 'WP_Customize_Cropped_Image_Control' );
    19711973                $this->register_control_type( 'WP_Customize_Site_Icon_Control' );
    19721974                $this->register_control_type( 'WP_Customize_Theme_Control' );
     1975                $this->register_control_type( 'WP_Customize_Post_Collection_Control' );
    19731976
    19741977                /* Themes */
    19751978
     
    23022305                        'section' => 'static_front_page',
    23032306                        'type' => 'dropdown-pages',
    23042307                ) );
     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                                'include_front_page' => true,
     2321                                'l10n'               => array(
     2322                                        'addPost'                => __( 'Add Section' ),
     2323                                        'addPosts'               => __( 'Add Sections' ),
     2324                                        'movedUp'                => __( 'Section moved up' ),
     2325                                        'movedDown'              => __( 'Section moved down' ),
     2326                                        'removePost'             => __( 'Remove Section' ),
     2327                                        'searchPosts'            => __( 'Search Sections' ),
     2328                                        'searchPostsPlaceholder' => __( 'Search sections&hellip;' ),
     2329                                ),
     2330                        ) ) );
     2331                }
    23052332        }
    23062333
    23072334        /**
     
    23812408        public function _render_custom_logo_partial() {
    23822409                return get_custom_logo();
    23832410        }
     2411
     2412        /**
     2413         * Ajax handler for finding posts.
     2414         *
     2415         * @since 4.7.0
     2416         *
     2417         * @see wp_ajax_find_posts()
     2418         */
     2419        public function ajax_find_posts() {
     2420                check_ajax_referer( 'find-posts' );
     2421
     2422                $post_types = array();
     2423
     2424                if ( ! empty( $_POST['post_types'] ) ) {
     2425                        $post_type_names = array_map( 'sanitize_text_field', wp_unslash( $_POST['post_types'] ) );
     2426                        foreach ( $post_type_names as $post_type ) {
     2427                                $post_types[ $post_type ] = get_post_type_object( $post_type );
     2428                        }
     2429                }
     2430
     2431                if ( empty( $post_types ) ) {
     2432                        $post_types['post'] = get_post_type_object( 'post' );
     2433                }
     2434
     2435                $args = array(
     2436                        'post_type'      => array_keys( $post_types ),
     2437                        'post_status'    => 'publish',
     2438                        'post__not_in'   => isset( $_POST['not_in'] ) ? wp_parse_id_list( $_POST['not_in'] ) : array(),
     2439                        'posts_per_page' => 50,
     2440                );
     2441
     2442                if ( ! empty( $_POST['s'] ) ) {
     2443                        $args['s'] = sanitize_text_field( wp_unslash( $_POST['s'] ) );
     2444                }
     2445
     2446                $posts = get_posts( $args );
     2447
     2448                if ( ! $posts ) {
     2449                        wp_send_json_error( __( 'No results found.' ) );
     2450                }
     2451
     2452                foreach ( $posts as $post ) {
     2453                        $data[] = array(
     2454                                'id'    => $post->ID,
     2455                                'title' => $post->post_title,
     2456                                'type'  => get_post_type_object( $post->post_type )->labels->singular_name,
     2457                        );
     2458                }
     2459
     2460                wp_send_json_success( $data );
     2461        }
     2462
     2463        /**
     2464         * Sanitization callback for lists of IDs.
     2465         *
     2466         * @since 4.7.0
     2467         *
     2468         * @param string $value Setting value.
     2469         * @return string Comma-separated list of IDs.
     2470         */
     2471        public function sanitize_id_list( $value ) {
     2472                return implode( ',', array_unique( array_filter( wp_parse_id_list( $value ) ) ) );
     2473        }
    23842474}
  • src/wp-includes/class-wp-query.php

     
    487487        private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
    488488
    489489        /**
     490         * Whether we're currently showing a static front page with sections.
     491         *
     492         * @since 4.7.0
     493         * @access private
     494         * @var boolean
     495         */
     496        private $front_page_with_sections = false;
     497
     498        /**
    490499         * Resets query flags to false.
    491500         *
    492501         * The query flags are what page info WordPress was able to figure out.
     
    521530                $this->is_robots = false;
    522531                $this->is_posts_page = false;
    523532                $this->is_post_type_archive = false;
     533                $this->front_page_with_sections = false;
    524534        }
    525535
    526536        /**
     
    974984                                        $qv['page'] = $qv['paged'];
    975985                                        unset($qv['paged']);
    976986                                }
     987                                // Add section pages, if they exist.
     988                                $front_page_sections = array_filter( wp_parse_id_list( get_theme_mod( 'front_page_sections' ) ) );
     989                                if ( $front_page_sections ) {
     990                                        $this->front_page_with_sections = true;
     991                                        if ( ! in_array( $qv['page_id'], $front_page_sections ) ) {
     992                                                array_unshift( $front_page_sections, $qv['page_id'] );
     993                                        }
     994                                        unset( $qv['page_id'] );
     995
     996                                        $qv['post__in'] = $front_page_sections;
     997                                        $qv['orderby'] = 'post__in';
     998                                }
    977999                        }
    9781000                }
    9791001
     
    10051027                        }
    10061028                }
    10071029
    1008                 if ( $qv['page_id'] ) {
     1030                if ( ! empty( $qv['page_id'] ) ) {
    10091031                        if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
    10101032                                $this->is_page = false;
    10111033                                $this->is_home = true;
     
    29943016                        if ( $q['cache_results'] )
    29953017                                update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
    29963018
    2997                         $this->post = reset( $this->posts );
     3019                        if ( $this->front_page_with_sections ) {
     3020                                $this->post = reset( $this->posts );
     3021                                do {
     3022                                        if ( $this->post && $this->post->ID == get_option( 'page_on_front' ) ) {
     3023                                                reset( $this->posts );
     3024                                                break;
     3025                                        }
     3026                                } while ( $this->post = next( $this->posts ) );
     3027                                if ( ! $this->post ) {
     3028                                        $this->post = reset( $this->posts );
     3029                                }
     3030                        } else {
     3031                                $this->post = reset( $this->posts );
     3032                        }
    29983033                } else {
    29993034                        $this->post_count = 0;
    30003035                        $this->posts = array();
  • 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 */
     17class 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         * Whether to include the front page in the post collection
     36         *
     37         * @since 4.7.0
     38         * @var bool
     39         */
     40        public $include_front_page = false;
     41
     42        /**
     43         * Localization strings.
     44         *
     45         * @since 4.7.0
     46         * @access public
     47         * @var array
     48         */
     49        public $l10n = array();
     50
     51        /**
     52         * Constructor.
     53         *
     54         * @since 4.7.0
     55         *
     56         * @param WP_Customize_Manager $manager Customizer bootstrap instance.
     57         * @param string               $id      Control ID.
     58         * @param array                $args    Optional. Arguments to override class property defaults.
     59         */
     60        public function __construct( $manager, $id, $args = array() ) {
     61                parent::__construct( $manager, $id, $args );
     62
     63                $this->l10n = wp_parse_args( $this->l10n, array(
     64                        'addPost'                => __( 'Add Post' ),
     65                        'addPosts'               => __( 'Add Posts' ),
     66                        'clearResults'           => __( 'Clear Results' ),
     67                        'moveUp'                 => __( 'Move up' ),
     68                        'moveDown'               => __( 'Move down' ),
     69                        'movedUp'                => __( 'Post moved up' ),
     70                        'movedDown'              => __( 'Post moved down' ),
     71                        'removePost'             => __( 'Remove Post' ),
     72                        'searchPosts'            => __( 'Search Posts' ),
     73                        'searchPostsPlaceholder' => __( 'Search posts&hellip;' ),
     74                ) );
     75        }
     76
     77        /**
     78         * Enqueue control related scripts/styles.
     79         *
     80         * @since 4.7.0
     81         */
     82        public function enqueue() {
     83                wp_enqueue_style( 'customize-post-collection' );
     84                wp_enqueue_script( 'customize-post-collection' );
     85
     86                add_action( 'customize_controls_print_footer_scripts', array( 'WP_Customize_Post_Collection_Control', 'print_templates' ) );
     87        }
     88
     89        /**
     90         * Refresh the parameters passed to the JavaScript via JSON.
     91         *
     92         * @since 4.7.0
     93         * @uses WP_Customize_Control::to_json()
     94         */
     95        public function to_json() {
     96                parent::to_json();
     97
     98                $this->json['l10n']             = $this->l10n;
     99                $this->json['posts']            = $this->get_posts();
     100                $this->json['postTypes']        = $this->post_types;
     101                $this->json['includeFrontPage'] = $this->include_front_page;
     102                $this->json['searchNonce']      = wp_create_nonce( 'find-posts' );
     103        }
     104
     105        /**
     106         * Don't render any content for this control from PHP.
     107         *
     108         * @since 4.7.0
     109         *
     110         * @see WP_Customize_Post_Collection_Control::content_template()
     111         */
     112        public function render_content() {}
     113
     114        /**
     115         * An Underscore (JS) template for this control's content (but not its container).
     116         *
     117         * @see WP_Customize_Control::print_template()
     118         *
     119         * @since 4.7.0
     120         */
     121        protected function content_template() {
     122                ?>
     123                <label>
     124                        <# if ( data.label ) { #>
     125                                <span class="customize-control-title">{{ data.label }}</span>
     126                        <# } #>
     127                        <# if ( data.description ) { #>
     128                                <span class="description customize-control-description">{{{ data.description }}}</span>
     129                        <# } #>
     130                </label>
     131                <?php
     132        }
     133
     134        /**
     135         * Print JavaScript templates in the Customizer footer.
     136         *
     137         * @since 4.7.0
     138         */
     139        public static function print_templates() {
     140                ?>
     141                <script type="text/html" id="tmpl-wp-item">
     142                        <div class="wp-item-header">
     143                                <h4 class="wp-item-title"><span>{{ data.title }}</span></h4>
     144
     145                                <# if ( ! data.includeFrontPage || data.id != wp.customize( 'page_on_front' )() ) { #>
     146                                        <button type="button" class="wp-item-delete button-link js-remove">
     147                                                <span class="screen-reader-text">{{ data.l10n.removePost }}</span>
     148                                        </button>
     149                                <# } #>
     150
     151                                <div class="wp-reorder-nav is-active">
     152                                        <button class="move-item-down" tabindex="0">{{ data.l10n.moveDown }}</button>
     153                                        <button class="move-item-up" tabindex="0">{{ data.l10n.moveUp }}</button>
     154                                </div>
     155                        </div>
     156                </script>
     157
     158                <script type="text/html" id="tmpl-customize-section-title">
     159                        <button type="button" class="customize-section-back" tabindex="-1">
     160                                <span class="screen-reader-text"><?php _e( 'Back' ); ?></span>
     161                        </button>
     162                        <h3>
     163                                <span class="customize-action">
     164                                        <?php
     165                                        /* translators: &#9656; is the unicode right-pointing triangle, and %s is the control label in the Customizer */
     166                                        printf( __( 'Customizing &#9656; %s' ), '{{ data.label }}' );
     167                                        ?>
     168                                </span>
     169                                {{ data.l10n.addPosts }}
     170                        </h3>
     171                </script>
     172
     173                <script type="text/html" id="tmpl-search-group">
     174                        <label class="screen-reader-text" for="search-group-field">{{ data.l10n.searchPosts }}</label>
     175                        <input type="text" id="search-group-field" placeholder="{{{ data.l10n.searchPostsPlaceholder }}}" class="search-group-field">
     176                        <div class="search-icon" aria-hidden="true"></div>
     177                        <button type="button" class="clear-results"><span class="screen-reader-text">{{ data.l10n.clearResults }}</span></button>
     178                </script>
     179
     180                <script type="text/html" id="tmpl-search-result">
     181                        <span class="search-results-item-type">{{ data.type }}</span>
     182                        <span class="search-results-item-title">{{ data.title }}</span>
     183
     184                        <button type="button" class="search-results-item-add button-link">
     185                                <span class="screen-reader-text">{{ data.l10n.addPost }}</span>
     186                        </button>
     187                </script>
     188                <?php
     189        }
     190
     191        /**
     192         * Retrieve posts.
     193         *
     194         * @since 4.7.0
     195         *
     196         * @return array
     197         */
     198        protected function get_posts() {
     199                $data     = array();
     200                $value    = $this->value();
     201                $post_ids = array_map( 'absint', explode( ',', $value ) );
     202
     203                if ( $this->include_front_page ) {
     204                        $front_page = get_option( 'page_on_front' );
     205                        if ( ! in_array( $front_page, $post_ids ) ) {
     206                                array_unshift( $post_ids, $front_page );
     207                        }
     208                }
     209
     210                if ( ! empty( $value ) ) {
     211                        $posts = get_posts( array(
     212                                'post_type'      => $this->post_types,
     213                                'post_status'    => 'any',
     214                                'post__in'       => $post_ids,
     215                                'orderby'        => 'post__in',
     216                                'posts_per_page' => 20,
     217                        ) );
     218                }
     219
     220                if ( ! empty( $posts ) ) {
     221                        $i = 0;
     222                        foreach ( $posts as $post ) {
     223                                $data[] = array(
     224                                        'id'    => $post->ID,
     225                                        'title' => $post->post_title,
     226                                        'order' => ++$i,
     227                                );
     228                        }
     229                }
     230
     231                return $data;
     232        }
     233}
  • src/wp-includes/default-filters.php

    Property changes on: src/wp-includes/customize/class-wp-customize-post-collection-control.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    427427
    428428// Canonical
    429429add_action( 'template_redirect', 'redirect_canonical' );
     430add_action( 'template_redirect', 'wp_redirect_front_page_sections' );
    430431add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
    431432
    432433// Shortcodes
  • src/wp-includes/link-template.php

     
    312312function get_page_link( $post = false, $leavename = false, $sample = false ) {
    313313        $post = get_post( $post );
    314314
    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' ) ) {
    316316                $link = home_url('/');
    317         else
     317        } elseif ( is_front_page_section( $post->ID ) ) {
     318                $link = get_front_page_section_url( $post->ID );
     319        } else {
    318320                $link = _get_page_link( $post, $leavename, $sample );
     321        }
    319322
    320323        /**
    321324         * Filters the permalink for a page.
     
    41424145         */
    41434146        return apply_filters( 'parent_theme_file_path', $path, $file );
    41444147}
     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 */
     4157function get_front_page_section_url( $post ) {
     4158        return home_url( '#post-' . get_post( $post )->ID );
     4159}
  • src/wp-includes/post-template.php

     
    479479                        $classes[] = 'format-standard';
    480480        }
    481481
     482        // Front page sections.
     483        if ( is_front_page() && is_front_page_section( $post->ID ) ) {
     484                $classes[] = 'front-page-section';
     485        }
     486
    482487        $post_password_required = post_password_required( $post->ID );
    483488
    484489        // Post requires password.
     
    17941799        echo $rows;
    17951800        echo "</ul>";
    17961801}
     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 */
     1811function 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

     
    476476        $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 );
    477477        $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 );
    478478
     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
    479481        $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
    480482
    481483        $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );
  • src/wp-includes/theme.php

     
    17301730
    17311731                                return false;
    17321732                        }
     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;
    17331744        }
    17341745
    17351746        $_wp_theme_features[ $feature ] = $args;
     
    18221833                case 'custom-logo' :
    18231834                case 'custom-header' :
    18241835                case 'custom-background' :
     1836                case 'front-page-sections' :
    18251837                        if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) )
    18261838                                return $_wp_theme_features[ $feature ][0][ $args[0] ];
    18271839                        return false;
     
    20822094                return;
    20832095        }
    20842096
    2085         require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; 
     2097        require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
    20862098        $GLOBALS['wp_customize'] = new WP_Customize_Manager();
    20872099}
    20882100