Ticket #37974: 37974.17.diff
File 37974.17.diff, 51.5 KB (added by , 8 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
687 687 688 688 /* Style for custom settings */ 689 689 690 #customize-control-front_page_sections { 691 border-top: 1px solid #ddd; 692 margin-top: 8px; 693 padding-top: 16px; 694 } 695 690 696 /** 691 697 * Dropdowns 692 698 */ … … 1205 1211 */ 1206 1212 1207 1213 /* higher specificity than .wp-core-ui .button */ 1214 #customize-theme-controls .add-new-item, 1208 1215 #customize-theme-controls .add-new-widget, 1209 1216 #customize-theme-controls .add-new-menu-item { 1210 1217 cursor: pointer; … … 1219 1226 outline: none; 1220 1227 } 1221 1228 1229 .reordering .add-new-item, 1222 1230 .reordering .add-new-widget, 1223 1231 .reordering .add-new-menu-item { 1224 1232 opacity: 0.2; … … 1226 1234 cursor: not-allowed; /* doesn't work in conjunction with pointer-events */ 1227 1235 } 1228 1236 1237 .add-new-item:before, 1229 1238 .add-new-widget:before, 1230 1239 .add-new-menu-item:before, 1231 1240 #available-menu-items .new-content-item .add-content:before { … … 1282 1291 color: #00a0d2; 1283 1292 } 1284 1293 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, 1285 1308 .widget-reorder-nav span, 1286 1309 .menu-item-reorder-nav button { 1287 1310 position: relative; … … 1296 1319 outline: none; 1297 1320 } 1298 1321 1322 .wp-reorder-nav button, 1299 1323 .menu-item-reorder-nav button { 1300 1324 width: 30px; 1301 1325 height: 40px; … … 1305 1329 box-shadow: none; 1306 1330 } 1307 1331 1332 .wp-reorder-nav button:before, 1308 1333 .widget-reorder-nav span:before, 1309 1334 .menu-item-reorder-nav button:before { 1310 1335 display: inline-block; … … 1320 1345 -moz-osx-font-smoothing: grayscale; 1321 1346 } 1322 1347 1348 .wp-reorder-nav button:hover, 1349 .wp-reorder-nav button:focus, 1323 1350 .widget-reorder-nav span:hover, 1324 1351 .widget-reorder-nav span:focus, 1325 1352 .menu-item-reorder-nav button:hover, … … 1328 1355 background: #eee; 1329 1356 } 1330 1357 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, 1331 1368 .move-widget-down:before, 1332 1369 .menus-move-down:before { 1333 1370 content: "\f347"; 1334 1371 } 1335 1372 1373 .move-item-up:before, 1336 1374 .move-widget-up:before, 1337 1375 .menus-move-up:before { 1338 1376 content: "\f343"; … … 1343 1381 .move-up-disabled .menus-move-up, 1344 1382 .move-down-disabled .menus-move-down, 1345 1383 .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 { 1347 1387 color: #d5d5d5; 1348 1388 background-color: #fff; 1349 1389 cursor: default; … … 1351 1391 } 1352 1392 1353 1393 /** 1354 * New widget and Add-menu-itemsmodes and panels1394 * New widget, Add-menu-items, and Drawer modes and panels 1355 1395 */ 1356 1396 1357 1397 .wp-full-overlay-main { … … 1359 1399 width: 100%; 1360 1400 } 1361 1401 1402 .customize-control.is-drawer-open .add-new-item, 1403 .customize-control.is-drawer-open .add-new-item:hover, 1362 1404 body.adding-widget .add-new-widget, 1363 1405 body.adding-widget .add-new-widget:hover, 1364 1406 .adding-menu-items .add-new-menu-item, … … 1372 1414 box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5); 1373 1415 } 1374 1416 1417 .customize-control.is-drawer-open .add-new-item:before, 1375 1418 body.adding-widget .add-new-widget:before, 1376 1419 .adding-menu-items .add-new-menu-item:before, 1377 1420 #accordion-section-add_menu .add-new-menu-item.open:before { … … 1380 1423 transform: rotate(45deg); 1381 1424 } 1382 1425 1426 .customize-drawer, 1383 1427 #available-widgets, 1384 1428 #available-menu-items { 1385 1429 position: absolute; … … 1398 1442 border-right: 1px solid #ddd; 1399 1443 } 1400 1444 1445 .customize-drawer .customize-section-title, 1401 1446 #available-widgets .customize-section-title, 1402 1447 #available-menu-items .customize-section-title { 1403 1448 display: none; … … 1425 1470 } 1426 1471 1427 1472 /* search field container */ 1473 .search-group, 1428 1474 #available-widgets-filter, 1429 1475 #available-menu-items-search .accordion-section-title { 1430 1476 padding: 13px 15px; … … 1433 1479 box-sizing: border-box; 1434 1480 } 1435 1481 1482 .search-group { 1483 position: relative; 1484 } 1485 1486 .search-group input, 1436 1487 #available-widgets-filter input, 1437 1488 #available-menu-items-search input { 1438 1489 width: 100%; … … 1441 1492 padding: 6px 30px; 1442 1493 } 1443 1494 1495 .search-group input::-ms-clear, 1444 1496 #available-widgets-filter input::-ms-clear, 1445 1497 #available-menu-items-search input::-ms-clear { 1446 1498 display: none; /* remove the "x" in IE, which conflicts with the "x" icon on button.clear-results */ 1447 1499 } 1448 1500 1501 .search-group .search-icon, 1449 1502 #available-menu-items-search .search-icon, 1450 1503 #available-widgets-filter .search-icon { 1451 1504 display: block; … … 1459 1512 color: #72777c; 1460 1513 } 1461 1514 1515 .search-group .clear-results, 1462 1516 #available-widgets-filter .clear-results, 1463 1517 #available-menu-items-search .clear-results { 1464 1518 position: absolute; … … 1475 1529 outline: 0; 1476 1530 } 1477 1531 1532 .search-group .clear-results, 1478 1533 #available-widgets-filter .clear-results, 1479 1534 #available-menu-items-search .clear-results, 1480 1535 #available-menu-items-search.loading .clear-results.is-visible { 1481 1536 display: none; 1482 1537 } 1483 1538 1539 .search-group .clear-results.is-visible, 1484 1540 #available-widgets-filter .clear-results.is-visible, 1485 1541 #available-menu-items-search .clear-results.is-visible { 1486 1542 display: block; 1487 1543 } 1488 1544 1545 .search-group .clear-results:before, 1489 1546 #available-widgets-filter .clear-results:before, 1490 1547 #available-menu-items-search .clear-results:before { 1491 1548 content: "\f335"; … … 1495 1552 -moz-osx-font-smoothing: grayscale; 1496 1553 } 1497 1554 1555 .search-group .clear-results:hover, 1556 .search-group .clear-results:focus, 1498 1557 #available-widgets-filter .clear-results:hover, 1499 1558 #available-widgets-filter .clear-results:focus, 1500 1559 #available-menu-items-search .clear-results:hover, … … 1502 1561 color: #dc3232; 1503 1562 } 1504 1563 1564 .search-group .clear-results:focus, 1505 1565 #available-widgets-filter .clear-results:focus, 1506 1566 #available-menu-items-search .clear-results:focus { 1507 1567 -webkit-box-shadow: … … 1512 1572 0 0 2px 1px rgba(30, 140, 190, .8); 1513 1573 } 1514 1574 1575 .search-group .search-icon:after, 1515 1576 #available-menu-items-search .search-icon:after, 1516 1577 #available-widgets-filter .search-icon:after { 1517 1578 content: "\f179"; … … 1521 1582 -moz-osx-font-smoothing: grayscale; 1522 1583 } 1523 1584 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 1524 1596 .no-widgets-found-message { 1525 1597 display: none; 1526 1598 margin: 0; … … 1558 1630 position: static; 1559 1631 } 1560 1632 1633 .customize-drawer.is-open { 1634 left: 0; 1635 visibility: visible; 1636 } 1637 1638 body.drawer-is-open .wp-full-overlay-main { 1639 left: 300px; 1640 } 1641 1642 body.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; 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 .wp-item.hide-delete .wp-item-delete { 1733 display: none; 1734 } 1735 1736 .wp-item.hide-delete .wp-reorder-nav { 1737 right: 0; 1738 } 1739 1740 /* Corner knockout to account for controls */ 1741 .wp-item.hide-delete .wp-item-title:before { 1742 width: 46px; 1743 } 1744 1745 /* Search results. */ 1746 1747 .search-results { 1748 padding: 1px 0 15px; 1749 } 1750 1751 .search-results ul { 1752 margin: -1px 0 0; 1753 } 1754 1755 .search-results-item { 1756 background: #fff; 1757 border-color: #ddd; 1758 border-style: solid; 1759 border-width: 1px 0; 1760 clear: both; 1761 cursor: pointer; 1762 line-height: 10px; 1763 margin: -1px 0 0 0; 1764 padding: 10px 15px; 1765 position: relative; 1766 } 1767 1768 .search-results-item-title { 1769 display: block; 1770 font-size: 13px; 1771 font-weight: 600; 1772 line-height: 20px; 1773 padding-left: 20px; 1774 word-wrap: break-word; 1775 } 1776 1777 .search-results-item-type { 1778 color: #666; 1779 float: right; 1780 font-size: 12px; 1781 line-height: 20px; 1782 padding-left: 10px; 1783 text-align: right; 1784 } 1785 1786 .search-results-item-add { 1787 color: #82878c; 1788 height: 38px; 1789 position: absolute; 1790 top: 1px; 1791 left: 1px; 1792 width: 30px; 1793 } 1794 1795 .search-results-item-add:before { 1796 -webkit-border-radius: 50%; 1797 border-radius: 50%; 1798 content: "\f543"; 1799 height: 20px; 1800 position: relative; 1801 top: 0; 1802 left: 2px; 1803 } 1804 1805 .search-results-item:hover { 1806 border-color: #999; 1807 color: #0073aa; 1808 z-index: 1; 1809 } 1810 1811 .search-results-item:hover .search-results-item-add:before { 1812 color: #0073aa; 1813 } 1814 1815 .search-results-item.is-selected .search-results-item-add:before { 1816 content: "\f147"; 1817 } 1818 1819 .search-results-item-add, 1820 .wp-item-delete { 1821 cursor: pointer; 1822 display: inline-block; 1823 font-family: dashicons; 1824 font-size: 20px; 1825 -webkit-font-smoothing: antialiased; 1826 font-style: normal; 1827 font-weight: normal; 1828 line-height: 1; 1829 text-align: center; 1830 text-decoration: inherit; 1831 vertical-align: top; 1832 } 1833 1834 .search-results.hide-type-label .search-results-item-type { 1835 display: none; 1836 } 1837 1561 1838 1562 1839 /* Responsive */ 1563 1840 .customize-controls-preview-toggle { … … 1679 1956 margin-top: 6px; 1680 1957 } 1681 1958 1959 body.drawer-is-open .customize-drawer, 1682 1960 body.adding-widget div#available-widgets, 1683 1961 body.adding-menu-items div#available-menu-items { 1684 1962 top: 46px; … … 1687 1965 width: 100%; 1688 1966 } 1689 1967 1968 .customize-drawer .customize-section-title, 1690 1969 #available-widgets .customize-section-title, 1691 1970 #available-menu-items .customize-section-title { 1692 1971 display: block; 1693 1972 margin: 0; 1694 1973 } 1695 1974 1975 .customize-drawer .customize-section-back, 1696 1976 #available-widgets .customize-section-back, 1697 1977 #available-menu-items .customize-section-back { 1698 1978 height: 69px; 1699 1979 } 1700 1980 1981 .customize-drawer .customize-section-title h3, 1701 1982 #available-widgets .customize-section-title h3, 1702 1983 #available-menu-items .customize-section-title h3 { 1703 1984 font-size: 20px; … … 1712 1993 text-overflow: ellipsis; 1713 1994 } 1714 1995 1996 .customize-drawer .customize-section-title .customize-action, 1715 1997 #available-widgets .customize-section-title .customize-action, 1716 1998 #available-menu-items .customize-section-title .customize-action { 1717 1999 font-size: 13px; -
src/wp-admin/includes/post.php
1285 1285 1286 1286 /** This filter is documented in wp-admin/edit-tag-form.php */ 1287 1287 $uri = apply_filters( 'editable_slug', $uri, $post ); 1288 if ( !empty($uri) ) 1289 $uri .= '/'; 1288 if ( ! empty( $uri ) ) { 1289 $uri .= is_front_page_section( $post->ID ) ? '.' : '/'; 1290 } 1290 1291 $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink); 1291 1292 } 1292 1293 -
src/wp-admin/includes/template.php
1712 1712 if ( 'page' === get_option( 'show_on_front' ) ) { 1713 1713 if ( intval( get_option( 'page_on_front' ) ) === $post->ID ) { 1714 1714 $post_states['page_on_front'] = __( 'Front Page' ); 1715 } elseif ( in_array( $post->ID, $front_page_sections = array_filter( wp_parse_id_list( get_option( 'front_page_sections' ) ) ), true ) ) { 1716 $post_states['front_page_section'] = __( 'Front Page Section' ); 1715 1717 } 1716 1718 1717 1719 if ( intval( get_option( 'page_for_posts' ) ) === $post->ID ) { -
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 labels: this.control.params.labels 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.params.labels.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 var view = this; 181 182 this.control = options.control; 183 184 this.listenTo( this.collection, 'add', this.addItem ); 185 this.listenTo( this.collection, 'add remove', this.updateOrder ); 186 this.listenTo( this.collection, 'reset', this.render ); 187 }, 188 189 render: function() { 190 this.$el.empty(); 191 this.collection.each( this.addItem, this ); 192 this.initializeSortable(); 193 return this; 194 }, 195 196 initializeSortable: function() { 197 this.$el.sortable({ 198 axis: 'y', 199 delay: 150, 200 forceHelperSize: true, 201 forcePlaceholderSize: true, 202 opacity: 0.6, 203 start: function( e, ui ) { 204 ui.placeholder.css( 'visibility', 'visible' ); 205 }, 206 update: _.bind(function() { 207 this.updateOrder(); 208 }, this ) 209 }); 210 }, 211 212 addItem: function( item ) { 213 var itemView = new api.PostCollection.ItemView({ 214 control: this.control, 215 model: item, 216 parent: this 217 }); 218 219 this.$el.append( itemView.render().el ); 220 }, 221 222 moveDown: function( model ) { 223 var index = this.collection.indexOf( model ), 224 $items = this.$el.children(); 225 226 if ( index < this.collection.length - 1 ) { 227 $items.eq( index ).insertAfter( $items.eq( index + 1 ) ); 228 this.updateOrder(); 229 wp.a11y.speak( this.control.params.labels.movedDown ); 230 } 231 }, 232 233 moveUp: function( model ) { 234 var index = this.collection.indexOf( model ), 235 $items = this.$el.children(); 236 237 if ( index > 0 ) { 238 $items.eq( index ).insertBefore( $items.eq( index - 1 ) ); 239 this.updateOrder(); 240 wp.a11y.speak( this.control.params.labels.movedUp ); 241 } 242 }, 243 244 updateOrder: function() { 245 _.each( this.$el.find( 'li' ), function( item, i ) { 246 var id = $( item ).data( 'post-id' ); 247 this.collection.get( id ).set( 'order', i ); 248 }, this ); 249 250 this.collection.sort(); 251 } 252 }); 253 254 api.PostCollection.ItemView = wp.Backbone.View.extend({ 255 tagName: 'li', 256 className: 'wp-item', 257 template: wp.template( 'wp-item' ), 258 259 events: { 260 'click .js-remove': 'destroy', 261 'click .move-item-up': 'moveUp', 262 'click .move-item-down': 'moveDown' 263 }, 264 265 initialize: function( options ) { 266 this.control = options.control; 267 this.parent = options.parent; 268 this.listenTo( this.model, 'destroy', this.remove ); 269 }, 270 271 render: function() { 272 var isFrontPage = this.model.get( 'id' ) == api( 'page_on_front' )(), 273 canDelete = ! this.control.params.includeFrontPage || ! isFrontPage, 274 data = _.extend( this.model.toJSON(), { 275 labels: this.control.params.labels, 276 includeFrontPage: this.control.params.includeFrontPage, 277 showDeleteButton: canDelete 278 }); 279 280 this.$el.html( this.template( data ) ); 281 this.$el.data( 'post-id', this.model.get( 'id' ) ); 282 283 if ( ! canDelete ) { 284 this.$el.addClass( 'hide-delete' ); 285 } 286 287 return this; 288 }, 289 290 moveDown: function( e ) { 291 e.preventDefault(); 292 this.parent.moveDown( this.model ); 293 }, 294 295 moveUp: function( e ) { 296 e.preventDefault(); 297 this.parent.moveUp( this.model ); 298 }, 299 300 /** 301 * Destroy the view's model. 302 * 303 * Avoid syncing to the server by triggering an event instead of 304 * calling destroy() directly on the model. 305 */ 306 destroy: function() { 307 this.model.trigger( 'destroy', this.model ); 308 }, 309 310 remove: function() { 311 this.$el.remove(); 312 } 313 }); 314 315 api.PostCollection.DrawerNoticeView = wp.Backbone.View.extend({ 316 tagName: 'div', 317 className: 'customize-drawer-notice', 318 319 initialize: function( options ) { 320 this.control = options.control; 321 this.listenTo( this.control.state, 'change:notice', this.render ); 322 }, 323 324 render: function() { 325 var notice = this.control.state.get( 'notice' ); 326 this.$el.toggle( !! notice.length ).text( notice ); 327 return this; 328 } 329 }); 330 331 api.PostCollection.SearchGroupView = wp.Backbone.View.extend({ 332 tagName: 'div', 333 className: 'search-group', 334 template: wp.template( 'search-group' ), 335 336 events: { 337 'click .clear-results' : 'clearResults', 338 'input input': 'search' 339 }, 340 341 initialize: function( options ) { 342 this.control = options.control; 343 this.listenTo( this.collection, 'add remove reset', this.updateClearResultsVisibility ); 344 }, 345 346 render: function() { 347 this.$el.html( this.template({ labels: this.control.params.labels }) ); 348 this.$clearResults = this.$( '.clear-results' ); 349 this.$field = this.$( '.search-group-field' ); 350 this.$spinner = this.$el.append( '<span class="search-group-spinner spinner" />' ).find( '.spinner' ); 351 this.updateClearResultsVisibility(); 352 return this; 353 }, 354 355 clearResults: function() { 356 this.collection.reset(); 357 this.$field.val( '' ).trigger( 'input' ).focus(); 358 }, 359 360 search: function() { 361 var view = this; 362 363 this.$el.addClass( 'is-searching' ); 364 this.$spinner.addClass( 'is-active' ); 365 366 clearTimeout( this.timeout ); 367 this.timeout = setTimeout(function() { 368 view.control.search( view.$field.val() ) 369 .always(function() { 370 view.$el.removeClass( 'is-searching' ); 371 view.$spinner.removeClass( 'is-active' ); 372 }); 373 }, 300 ); 374 }, 375 376 updateClearResultsVisibility: function() { 377 this.$clearResults.toggleClass( 'is-visible', !! this.collection.length && '' !== this.$field.val() ); 378 } 379 }); 380 381 api.PostCollection.SearchResultsView = wp.Backbone.View.extend({ 382 tagName: 'div', 383 className: 'search-results', 384 385 initialize: function( options ) { 386 this.control = options.control; 387 this.listenTo( this.collection, 'reset', this.render ); 388 }, 389 390 render: function() { 391 this.$list = this.$el.html( '<ul />' ).find( 'ul' ); 392 this.$el.toggleClass( 'hide-type-label', 1 === this.control.params.postTypes.length ); 393 394 if ( this.collection.length ) { 395 this.collection.each( this.addItem, this ); 396 } else { 397 this.$el.empty(); 398 } 399 400 return this; 401 }, 402 403 addItem: function( model ) { 404 this.views.add( 'ul', new api.PostCollection.SearchResultView({ 405 control: this.control, 406 model: model 407 })); 408 } 409 }); 410 411 api.PostCollection.SearchResultView = wp.Backbone.View.extend({ 412 tagName: 'li', 413 className: 'search-results-item', 414 template: wp.template( 'search-result' ), 415 416 events: { 417 'click': 'addItem' 418 }, 419 420 initialize: function( options ) { 421 this.control = options.control; 422 this.listenTo( this.control.posts, 'add remove reset', this.updateSelectedClass ); 423 }, 424 425 render: function() { 426 var data = _.extend( this.model.toJSON(), { 427 labels: this.control.params.labels 428 }); 429 430 this.$el.html( this.template( data ) ); 431 this.updateSelectedClass(); 432 433 return this; 434 }, 435 436 addItem: function() { 437 this.control.posts.add( this.model ); 438 }, 439 440 updateSelectedClass: function() { 441 this.$el.toggleClass( 'is-selected', !! this.control.posts.findWhere({ id: this.model.get( 'id' ) }) ); 442 } 443 }); 444 445 api.PostCollection.PostCollectionControl = api.Control.extend({ 446 ready: function() { 447 var controlView, drawerView, 448 control = this, 449 section = api.section( this.section() ); 450 451 this.drawer = new api.DrawerModel(); 452 api.drawerManager.add( this.drawer ); 453 454 this.posts = new api.PostCollection.PostsCollection( this.params.posts ); 455 this.results = new api.PostCollection.PostsCollection(); 456 delete this.params.posts; 457 458 this.state = new Backbone.Model({ 459 notice: '' 460 }); 461 462 if ( this.params.includeFrontPage ) { 463 // Add the front page when it changes. 464 api( 'page_on_front', function( setting ) { 465 setting.bind( _.bind( control.onPageOnFrontChange, control ) ); 466 }); 467 } 468 469 controlView = new api.PostCollection.ControlView({ 470 el: this.container, 471 collection: this.posts, 472 control: this, 473 data: this.params, 474 setting: this.setting 475 }); 476 477 controlView.render(); 478 479 drawerView = new api.DrawerView({ 480 controller: this.drawer 481 }); 482 483 drawerView.views.set([ 484 new api.PostCollection.CustomizeSectionTitleView({ 485 control: this 486 }), 487 new api.PostCollection.SearchGroupView({ 488 collection: this.results, 489 control: this 490 }), 491 new api.PostCollection.DrawerNoticeView({ 492 control: this 493 }), 494 new api.PostCollection.SearchResultsView({ 495 collection: this.results, 496 control: this 497 }) 498 ]); 499 500 $( '.wp-full-overlay' ).append( drawerView.render().$el ); 501 502 section.expanded.bind(function( isOpen ) { 503 if ( ! isOpen ) { 504 control.drawer.close(); 505 } 506 }); 507 }, 508 509 onPageOnFrontChange: function( value ) { 510 var id = parseInt( value, 10 ), 511 posts = this.posts.toJSON(), 512 pageOnFrontControl = api.control( 'page_on_front' ); 513 514 if ( id > 1 && ! this.posts.findWhere({ id: id }) ) { 515 posts.unshift({ 516 id: id, 517 title: pageOnFrontControl.container.find( 'option:selected' ).text() 518 }); 519 } 520 521 if ( 2 === posts.length ) { 522 posts = posts.shift(); 523 } 524 525 // Reset the collection to re-render the view. 526 this.posts.reset( posts ); 527 }, 528 529 search: function( query ) { 530 var control = this, 531 promises = []; 532 533 _.each( this.params.postTypes, function( postType ) { 534 var collectionType = postType[0].toUpperCase() + postType.slice( 1 ) + 's'; 535 536 var posts = new wp.api.collections[ collectionType ]( { 537 search: query, 538 status: 'publish' 539 } ); 540 541 promises.push( posts.fetch() ); 542 } ); 543 544 return $.when.apply( $, promises ).done( function() { 545 var responses = []; 546 547 _.each( arguments, function( response ) { 548 responses = responses.concat( response[0] ); 549 } ); 550 551 control.results.reset( responses ); 552 control.state.set( 'notice', '' ); 553 } ).fail( function( response ) { 554 control.results.reset(); 555 control.state.set( 'notice', response ); 556 } ); 557 } 558 }); 559 560 /** 561 * Toggle the front page sections control based on front page settings. 562 */ 563 function toggleFrontPageSectionsControl() { 564 var controlId = 'front_page_sections', 565 showOnFront = api( 'show_on_front' )(), 566 pageOnFront = api( 'page_on_front' )(), 567 isVisible = 'page' === showOnFront && parseInt( pageOnFront ) > 0; 568 569 if ( api.control.has( controlId ) ) { 570 api.control( controlId ).container.toggle( isVisible ); 571 } 572 } 573 574 /** 575 * Extends wp.customize.controlConstructor with control constructor for 576 * post_collection. 577 */ 578 $.extend( api.controlConstructor, { 579 post_collection: api.PostCollection.PostCollectionControl 580 }); 581 582 /** 583 * Create a global drawer manager. 584 */ 585 api.drawerManager = new api.DrawerManager(); 586 587 /** 588 * Toggle an HTML class on the body when drawers are opened or closed. 589 */ 590 $( document ).ready(function() { 591 var $body = $( document.body ); 592 593 api.drawerManager.on( 'change:status', function() { 594 if ( api.drawerManager.findWhere({ status: 'open' }) ) { 595 $body.addClass( 'drawer-is-open' ); 596 } else { 597 $body.removeClass( 'drawer-is-open' ); 598 } 599 }); 600 }); 601 602 /** 603 * Bind events to toggle visibilty of the front page sections control. 604 */ 605 api.bind( 'ready', function() { 606 api( 'show_on_front' ).bind( toggleFrontPageSectionsControl ); 607 api( 'page_on_front' ).bind( toggleFrontPageSectionsControl ); 608 api.section( 'static_front_page' ).expanded.bind( toggleFrontPageSectionsControl ); 609 }); 610 611 })( 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
655 655 exit; 656 656 } 657 657 } 658 659 /** 660 * Redirect front page section permalinks to the anchor 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 is_front_page() 669 || is_home() 670 || ! is_singular() 671 || ! is_front_page_section( $object_id ) 672 ) { 673 return; 674 } 675 676 wp_redirect( get_permalink( $object_id ) ); 677 exit; 678 } -
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 … … 1970 1971 $this->register_control_type( 'WP_Customize_Cropped_Image_Control' ); 1971 1972 $this->register_control_type( 'WP_Customize_Site_Icon_Control' ); 1972 1973 $this->register_control_type( 'WP_Customize_Theme_Control' ); 1974 $this->register_control_type( 'WP_Customize_Post_Collection_Control' ); 1973 1975 1974 1976 /* Themes */ 1975 1977 … … 2302 2304 'section' => 'static_front_page', 2303 2305 'type' => 'dropdown-pages', 2304 2306 ) ); 2307 2308 $this->add_setting( 'front_page_sections', array( 2309 'type' => 'option', 2310 'capability' => 'manage_options', 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' => apply_filters( 'front_page_sections_post_types', array( 'page', 'post' ) ), 2320 'include_front_page' => true, 2321 'labels' => 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…' ), 2329 ), 2330 ) ) ); 2305 2331 } 2306 2332 2307 2333 /** … … 2381 2407 public function _render_custom_logo_partial() { 2382 2408 return get_custom_logo(); 2383 2409 } 2410 2411 /** 2412 * Sanitization callback for lists of IDs. 2413 * 2414 * @since 4.7.0 2415 * 2416 * @param string $value Setting value. 2417 * @return string Comma-separated list of IDs. 2418 */ 2419 public function sanitize_id_list( $value ) { 2420 return implode( ',', array_unique( array_filter( wp_parse_id_list( $value ) ) ) ); 2421 } 2384 2422 } -
src/wp-includes/class-wp-query.php
487 487 private $compat_methods = array( 'init_query_flags', 'parse_tax_query' ); 488 488 489 489 /** 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 $is_front_page_with_sections = false; 497 498 /** 490 499 * Resets query flags to false. 491 500 * 492 501 * The query flags are what page info WordPress was able to figure out. … … 521 530 $this->is_robots = false; 522 531 $this->is_posts_page = false; 523 532 $this->is_post_type_archive = false; 533 $this->is_front_page_with_sections = false; 524 534 } 525 535 526 536 /** … … 976 986 $qv['page'] = $qv['paged']; 977 987 unset($qv['paged']); 978 988 } 989 990 // Add section pages, if they exist. 991 if ( $this->is_main_query() ) { 992 $front_page_sections = array_filter( wp_parse_id_list( get_option( 'front_page_sections' ) ) ); 993 if ( $front_page_sections ) { 994 $this->is_front_page_with_sections = true; 995 if ( ! in_array( $qv['page_id'], $front_page_sections ) ) { 996 array_unshift( $front_page_sections, $qv['page_id'] ); 997 } 998 999 $qv['post__in'] = $front_page_sections; 1000 $qv['orderby'] = 'post__in'; 1001 } 1002 } 979 1003 } 980 1004 } 981 1005 … … 1007 1031 } 1008 1032 } 1009 1033 1010 if ( $qv['page_id']) {1034 if ( ! $this->is_front_page_with_sections && ! empty( $qv['page_id'] ) ) { 1011 1035 if ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) { 1012 1036 $this->is_page = false; 1013 1037 $this->is_home = true; … … 1970 1994 $where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)"; 1971 1995 } 1972 1996 1973 if ( $q['page_id'] ) {1997 if ( ! $this->is_front_page_with_sections && $q['page_id'] ) { 1974 1998 if ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) { 1975 1999 $q['p'] = $q['page_id']; 1976 2000 $where = " AND {$wpdb->posts}.ID = " . $q['page_id']; … … 3006 3030 if ( $q['cache_results'] ) 3007 3031 update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']); 3008 3032 3009 $this->post = reset( $this->posts ); 3033 if ( $this->is_front_page_with_sections ) { 3034 $this->post = reset( $this->posts ); 3035 do { 3036 if ( $this->post && $this->post->ID == get_option( 'page_on_front' ) ) { 3037 reset( $this->posts ); 3038 break; 3039 } 3040 } while ( $this->post = next( $this->posts ) ); 3041 if ( ! $this->post ) { 3042 $this->post = reset( $this->posts ); 3043 } 3044 } else { 3045 $this->post = reset( $this->posts ); 3046 } 3010 3047 } else { 3011 3048 $this->post_count = 0; 3012 3049 $this->posts = array(); … … 3107 3144 3108 3145 $post = $this->next_post(); 3109 3146 $this->setup_postdata( $post ); 3147 3148 if ( $this->is_front_page_with_sections && $post ) { 3149 echo '<a id="' . str_replace( '/', '.', get_page_uri( $post->ID ) ) . '"></a>'; 3150 } 3110 3151 } 3111 3152 3112 3153 /** -
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 * 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 * Labels. 44 * 45 * @since 4.7.0 46 * @access public 47 * @var array 48 */ 49 public $labels = 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->labels = wp_parse_args( $this->labels, 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…' ), 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['labels'] = $this->labels; 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.rendered }}</span></h4> 144 145 <# if ( data.showDeleteButton ) { #> 146 <button type="button" class="wp-item-delete button-link js-remove"> 147 <span class="screen-reader-text">{{ data.labels.removePost }}</span> 148 </button> 149 <# } #> 150 151 <div class="wp-reorder-nav is-active"> 152 <button class="move-item-down" tabindex="0">{{ data.labels.moveDown }}</button> 153 <button class="move-item-up" tabindex="0">{{ data.labels.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: ▸ is the unicode right-pointing triangle, and %s is the control label in the Customizer */ 166 printf( __( 'Customizing ▸ %s' ), '{{ data.label }}' ); 167 ?> 168 </span> 169 {{ data.labels.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.labels.searchPosts }}</label> 175 <input type="text" id="search-group-field" placeholder="{{{ data.labels.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.labels.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.rendered }}</span> 183 184 <button type="button" class="search-results-item-add button-link"> 185 <span class="screen-reader-text">{{ data.labels.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 $value = $this->value(); 200 $post_ids = array_filter( array_map( 'absint', explode( ',', $value ) ) ); 201 202 if ( $this->include_front_page ) { 203 $front_page = get_option( 'page_on_front' ); 204 if ( ! in_array( $front_page, $post_ids ) ) { 205 array_unshift( $post_ids, $front_page ); 206 } 207 } 208 209 $posts = array(); 210 if ( ! empty( $post_ids ) ) { 211 foreach ( $this->post_types as $post_type ) { 212 $request = new WP_REST_Request( 'GET', "/wp/v2/{$post_type}s" ); 213 214 $request->set_param( 'status', 'any' ); 215 $request->set_param( 'include', $post_ids ); 216 $request->set_param( 'per_page', 20 ); 217 218 $response = rest_do_request( $request ); 219 220 $posts = array_merge( $posts, $response->get_data() ); 221 } 222 223 } 224 225 if ( ! empty( $posts ) ) { 226 $i = 0; 227 foreach ( $posts as $index => $post ) { 228 $posts[ $index ]['order'] = ++$i; 229 } 230 } 231 232 usort( $posts, function ( $a, $b ) use ( $post_ids ) { 233 $index_a = array_search( $a['id'], $post_ids ); 234 $index_b = array_search( $b['id'], $post_ids ); 235 236 if ( $index_a === $index_b ) { 237 return 0; 238 } 239 240 return ( $index_a < $index_b ) ? -1 : 1; 241 } ); 242 243 return $posts; 244 } 245 } -
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
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 else317 } else { 318 318 $link = _get_page_link( $post, $leavename, $sample ); 319 } 319 320 320 321 /** 321 322 * Filters the permalink for a page. … … 359 360 $link = str_replace('%pagename%', get_page_uri( $post ), $link); 360 361 } 361 362 362 $link = home_url($link); 363 $link = user_trailingslashit($link, 'page'); 363 if ( is_front_page_section( $post->ID ) ) { 364 $link = home_url( '#' . str_replace( '/', '.', $link ) ); 365 } else { 366 $link = home_url($link); 367 $link = user_trailingslashit($link, 'page'); 368 } 364 369 } else { 365 370 $link = home_url( '?page_id=' . $post->ID ); 366 371 } -
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. … … 1802 1807 echo $rows; 1803 1808 echo "</ul>"; 1804 1809 } 1810 1811 /** 1812 * Whether a post is a front page section. 1813 * 1814 * @since 4.7.0 1815 * 1816 * @param int $post_id Post ID. 1817 * @return bool 1818 */ 1819 function is_front_page_section( $post_id ) { 1820 $section_ids = array_filter( wp_parse_id_list( get_option( 'front_page_sections' ) ) ); 1821 return in_array( intval( $post_id ), $section_ids, true ); 1822 } -
src/wp-includes/script-loader.php
479 479 $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu' ), false, 1 ); 480 480 $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 ); 481 481 482 $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', 'wp-api' ), false, 1 ); 483 482 484 $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 ); 483 485 484 486 $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 ); -
tests/phpunit/tests/ajax/FindPosts.php
1 <?php 2 3 /** 4 * Testing ajax post finding. 5 * 6 * @group ajax 7 */ 8 class Tests_Ajax_Find_Posts extends WP_Ajax_UnitTestCase { 9 10 public function test_wp_ajax_find_posts_returns_public_posts() { 11 12 $this->_setRole( 'administrator' ); 13 14 $page_id = self::factory()->post->create( array( 15 'post_type' => 'page', 16 ) ); 17 $page = get_post( $page_id ); 18 19 $post_id = $this->front_page_section = self::factory()->post->create(); 20 $post = get_post( $post_id ); 21 22 // Set up a default request 23 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 24 $_POST['ps'] = ''; 25 26 // Make the request 27 try { 28 $this->_handleAjax( 'find_posts' ); 29 } catch ( WPAjaxDieContinueException $e ) { 30 unset( $e ); 31 } 32 33 // Get the response. 34 $response = json_decode( $this->_last_response, true ); 35 36 $this->assertThat( $response['data'], $this->stringContains( $page->post_title ) ); 37 $this->assertThat( $response['data'], $this->stringContains( $post->post_title ) ); 38 } 39 40 public function test_wp_ajax_find_posts_does_not_return_attachments() { 41 42 $this->_setRole( 'administrator' ); 43 44 $attachment_id = $this->front_page_section = self::factory()->post->create(array( 45 'post_type' => 'attachment', 46 ) ); 47 $attachment = get_post( $attachment_id ); 48 49 // Set up a default request 50 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 51 $_POST['ps'] = ''; 52 53 // Make the request 54 try { 55 $this->_handleAjax( 'find_posts' ); 56 } catch ( WPAjaxDieContinueException $e ) { 57 unset( $e ); 58 } 59 60 // Get the response. 61 $response = json_decode( $this->_last_response, true ); 62 63 $this->assertThat( $response['data'], $this->logicalNot( $this->stringContains( $attachment->post_title ) ) ); 64 } 65 66 public function test_wp_ajax_find_posts_searches() { 67 68 $this->_setRole( 'administrator' ); 69 70 $post_id = $this->front_page_section = self::factory()->post->create(); 71 $post = get_post( $post_id ); 72 73 $post2_id = $this->front_page_section = self::factory()->post->create(); 74 $post2 = get_post( $post2_id ); 75 76 // Set up a default request 77 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 78 $_POST['ps'] = $post->post_title; 79 80 // Make the request 81 try { 82 $this->_handleAjax( 'find_posts' ); 83 } catch ( WPAjaxDieContinueException $e ) { 84 unset( $e ); 85 } 86 87 // Get the response. 88 $response = json_decode( $this->_last_response, true ); 89 90 $this->assertThat( $response['data'], $this->stringContains( $post->post_title ) ); 91 $this->assertThat( $response['data'], $this->logicalNot( $this->stringContains( $post2->post_title ) ) ); 92 } 93 } -
tests/phpunit/tests/query/frontPageSections.php
Property changes on: tests/phpunit/tests/ajax/FindPosts.php ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property
1 <?php 2 3 /** 4 * @group query 5 * @group front-page-sections 6 */ 7 8 class Front_Page_Sections_Query extends WP_UnitTestCase { 9 private $page_on_front; 10 private $front_page_section; 11 12 function setUp() { 13 $this->page_on_front = self::factory()->post->create( array( 14 'post_type' => 'page', 15 ) ); 16 $this->front_page_section = self::factory()->post->create( array( 17 'post_type' => 'page', 18 ) ); 19 20 update_option( 'show_on_front', 'page' ); 21 update_option( 'page_on_front', $this->page_on_front ); 22 update_option( 'front_page_sections', $this->front_page_section ); 23 } 24 25 function tearDown() { 26 global $wp_the_query; 27 $wp_the_query->init(); 28 29 update_option( 'show_on_front', 'posts' ); 30 delete_option( 'page_on_front' ); 31 delete_option( 'front_page_sections' ); 32 } 33 34 function test_page_id_is_set() { 35 global $wp_the_query; 36 $wp_the_query->query( array() ); 37 38 $this->assertEquals( $this->page_on_front, $wp_the_query->query_vars['page_id'] ); 39 } 40 41 function test_all_posts_are_returned() { 42 global $wp_the_query; 43 $wp_the_query->query( array() ); 44 45 $this->assertCount( 2, $wp_the_query->posts ); 46 } 47 48 function test_posts_are_ordered() { 49 global $wp_the_query; 50 51 update_option( 'front_page_sections', "$this->front_page_section,$this->page_on_front" ); 52 53 $wp_the_query->query( array() ); 54 55 $this->assertCount( 2, $wp_the_query->posts ); 56 $this->assertEquals( $this->front_page_section, $wp_the_query->posts[0]->ID ); 57 $this->assertEquals( $this->page_on_front, $wp_the_query->posts[1]->ID ); 58 $this->assertEquals( $this->page_on_front, $wp_the_query->post->ID ); 59 } 60 61 function test_lots_of_subsections_are_returned() { 62 global $wp_the_query; 63 64 $subsections = array(); 65 for( $i = 0; $i < 10; $i++ ) { 66 $subsections[] = self::factory()->post->create( array( 67 'post_type' => 'page', 68 ) ); 69 } 70 71 update_option( 'front_page_sections', implode(',', $subsections ) ); 72 73 $wp_the_query->query( array() ); 74 75 $this->assertCount( 11, $wp_the_query->posts ); 76 } 77 78 function test_get_post_doesnt_get_subsections() { 79 $post = get_post( $this->page_on_front ); 80 $this->assertEquals( $this->page_on_front, $post->ID ); 81 } 82 83 function test_get_pages_doesnt_get_subsections() { 84 $pages = get_pages( array( 'include' => array( $this->page_on_front ) ) ); 85 86 $this->assertCount( 1, $pages ); 87 $this->assertEquals( $this->page_on_front, $pages[0]->ID ); 88 } 89 90 function test_get_posts_doesnt_get_subsections() { 91 $pages = get_posts( array( 'include' => array( $this->page_on_front ), 'post_type' => 'page' ) ); 92 93 $this->assertCount( 1, $pages ); 94 $this->assertEquals( $this->page_on_front, $pages[0]->ID ); 95 } 96 97 function test_the_post_outputs_anchor_tag() { 98 global $wp_the_query; 99 $wp_the_query->query( array() ); 100 101 ob_start(); 102 while( $wp_the_query->have_posts() ) { 103 $wp_the_query->the_post(); 104 } 105 $actual = ob_get_contents(); 106 ob_end_clean(); 107 108 $expected = '<a id="' . str_replace( '/', '.', get_page_uri( $this->page_on_front ) ) . '"></a>'; 109 $expected .= '<a id="' . str_replace( '/', '.', get_page_uri( $this->front_page_section ) ) . '"></a>'; 110 111 $this->assertEquals( $expected, $actual ); 112 } 113 114 function test_new_wp_query_doesnt_output_anchor_tag() { 115 $query = new WP_Query(); 116 $query->query( array() ); 117 118 ob_start(); 119 while( $query->have_posts() ) { 120 $query->the_post(); 121 } 122 $actual = ob_get_contents(); 123 ob_end_clean(); 124 125 $this->assertEmpty( $actual ); 126 } 127 } 128 No newline at end of file