Ticket #37974: 37974.18.diff
File 37974.18.diff, 53.6 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 } 1561 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 1838 1562 1839 /* Responsive */ 1563 1840 .customize-controls-preview-toggle { 1564 1841 display: none; … … 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/ajax-actions.php
1751 1751 function wp_ajax_find_posts() { 1752 1752 check_ajax_referer( 'find-posts' ); 1753 1753 1754 $post_types = get_post_types( array( 'public' => true ), 'objects' ); 1755 unset( $post_types['attachment'] ); 1754 $post_types = array(); 1755 if ( empty( $_POST['post_types'] ) ) { 1756 $post_types = get_post_types( array( 'public' => true ), 'objects' ); 1757 unset( $post_types['attachment'] ); 1758 } else { 1759 $post_type_names = array_map( 'sanitize_text_field', wp_unslash( $_POST['post_types'] ) ); 1760 foreach ( $post_type_names as $post_type ) { 1761 $post_types[ $post_type ] = get_post_type_object( $post_type ); 1762 } 1763 } 1756 1764 1757 $s = wp_unslash( $_POST['ps'] );1758 1765 $args = array( 1759 'post_type' => array_keys( $post_types ),1760 'post_status' =>'any',1766 'post_type' => array_keys( $post_types ), 1767 'post_status' => isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : 'any', 1761 1768 'posts_per_page' => 50, 1762 1769 ); 1763 if ( '' !== $s )1764 $args['s'] = $s;1765 1770 1771 if ( ! empty( $_POST['ps'] ) ) { 1772 $args['s'] = wp_unslash( $_POST['ps'] ); 1773 } 1774 1766 1775 $posts = get_posts( $args ); 1767 1776 1768 1777 if ( ! $posts ) { … … 1769 1778 wp_send_json_error( __( 'No items found.' ) ); 1770 1779 } 1771 1780 1781 if ( isset( $_POST['format'] ) && 'json' === $_POST['format'] ) { 1782 foreach ( $posts as $post ) { 1783 $data[] = array( 1784 'id' => $post->ID, 1785 'title' => $post->post_title, 1786 'type' => $post_types[ $post->post_type ]->labels->singular_name, 1787 ); 1788 } 1789 1790 wp_send_json_success( $data ); 1791 } 1792 1772 1793 $html = '<table class="widefat"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th class="no-break">'.__('Type').'</th><th class="no-break">'.__('Date').'</th><th class="no-break">'.__('Status').'</th></tr></thead><tbody>'; 1773 1794 $alt = ''; 1774 1795 foreach ( $posts as $post ) { -
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.PostModel = Backbone.Model.extend({ 10 defaults: { 11 sortableOrder: 0, 12 title: '' 13 } 14 }); 15 16 api.PostsCollection = Backbone.Collection.extend({ 17 model: api.PostModel, 18 comparator: 'sortableOrder' 19 }); 20 21 api.Drawer = api.Class.extend({ 22 type: 'drawer', 23 24 initialize: function( id, options ) { 25 var drawer = this; 26 27 _.extend( this, options || {} ); 28 this.id = id; 29 30 _.bindAll( this, 'collapseOtherDrawers' ); 31 this.container = $( '<div class="customize-drawer" />' ); 32 33 this.deferred = { 34 embedded: new $.Deferred() 35 }; 36 37 this.control = new api.Value(); 38 this.control.set( options.control ); 39 40 this.expanded = new api.Value(); 41 this.expanded.set( false ); 42 this.expanded.bind( this.collapseOtherDrawers ); 43 44 drawer.embed(); 45 drawer.deferred.embedded.done(function () { 46 drawer.ready(); 47 }); 48 49 // Collapse the drawer when the control's section is collapsed. 50 api.control( this.control(), function( control ) { 51 api.section( control.section() ).expanded.bind(function( isExpanded ) { 52 if ( ! isExpanded ) { 53 drawer.collapse(); 54 } 55 }); 56 }); 57 }, 58 59 embed: function () { 60 $( '.wp-full-overlay' ).append( this.container ); 61 62 this.view = new wp.Backbone.View({ 63 el: this.container 64 }); 65 66 this.view.views.add( 67 new this.TitleView({ 68 drawer: this 69 }) 70 ); 71 72 this.deferred.embedded.resolve(); 73 }, 74 75 ready: function() {}, 76 77 collapse: function() { 78 this.expanded.set( false ); 79 this.container.removeClass( 'is-open' ); 80 $( document.body ).removeClass( 'drawer-is-open' ); 81 api.control( this.control() ).container.removeClass( 'is-drawer-open' ); 82 }, 83 84 expand: function() { 85 this.expanded.set( true ); 86 this.container.addClass( 'is-open' ); 87 $( document.body ).addClass( 'drawer-is-open' ); 88 api.control( this.control() ).container.addClass( 'is-drawer-open' ); 89 }, 90 91 toggle: function() { 92 if ( this.expanded() ) { 93 this.collapse(); 94 } else { 95 this.expand(); 96 } 97 }, 98 99 collapseOtherDrawers: function( isExpanded ) { 100 if ( isExpanded ) { 101 api.drawer.each(function( drawer ) { 102 if ( drawer.id !== this.id ) { 103 drawer.collapse(); 104 } 105 }, this ); 106 107 if ( this.expanded() ) { 108 $( document.body ).addClass( 'drawer-is-open' ); 109 } 110 } 111 }, 112 113 TitleView: wp.Backbone.View.extend({ 114 className: 'customize-drawer-title customize-section-title', 115 template: wp.template( 'customize-drawer-title' ), 116 117 events: { 118 'click .customize-section-back': 'collapseDrawer' 119 }, 120 121 initialize: function( options ) { 122 this.drawer = options.drawer; 123 }, 124 125 render: function() { 126 this.$el.html( this.template( this.drawer.labels ) ); 127 return this; 128 }, 129 130 collapseDrawer: function( e ) { 131 e.preventDefault(); 132 this.drawer.collapse(); 133 } 134 }) 135 }); 136 137 api.PostSearchDrawer = api.Drawer.extend({ 138 type: 'post-search-drawer', 139 140 ready: function() { 141 var drawer = this; 142 143 this.results = new api.PostsCollection(); 144 145 this.state = new Backbone.Model({ 146 notice: '' 147 }); 148 149 this.view.views.add([ 150 new this.SearchFormView({ 151 collection: this.results, 152 drawer: this 153 }), 154 new this.NoticeView({ 155 drawer: this 156 }), 157 new this.SearchResultsView({ 158 collection: this.results, 159 drawer: this, 160 selection: this.selection 161 }) 162 ]); 163 164 this.expanded.bind(function( isExpanded ) { 165 if ( isExpanded && drawer.results.length < 1 ) { 166 drawer.search(); 167 } 168 }); 169 }, 170 171 search: function( query ) { 172 var drawer = this; 173 174 return wp.ajax.post( 'find_posts', { 175 ps: query, 176 post_types: this.postTypes, 177 post_status: 'publish', 178 format: 'json', 179 _ajax_nonce: this.searchNonce 180 }).done(function( response ) { 181 drawer.results.reset( response ); 182 drawer.state.set( 'notice', '' ); 183 }).fail(function( response ) { 184 drawer.results.reset(); 185 drawer.state.set( 'notice', response ); 186 }); 187 }, 188 189 NoticeView: wp.Backbone.View.extend({ 190 tagName: 'div', 191 className: 'customize-drawer-notice', 192 193 initialize: function( options ) { 194 this.drawer = options.drawer; 195 this.listenTo( this.drawer.state, 'change:notice', this.render ); 196 }, 197 198 render: function() { 199 var notice = this.drawer.state.get( 'notice' ); 200 this.$el.toggle( !! notice.length ).text( notice ); 201 return this; 202 } 203 }), 204 205 SearchFormView: wp.Backbone.View.extend({ 206 tagName: 'div', 207 className: 'search-group', 208 template: wp.template( 'search-group' ), 209 210 events: { 211 'click .clear-results' : 'clearResults', 212 'input input': 'search' 213 }, 214 215 initialize: function( options ) { 216 this.collection = options.collection; 217 this.drawer = options.drawer; 218 219 this.listenTo( this.collection, 'add remove reset', this.updateClearResultsVisibility ); 220 }, 221 222 render: function() { 223 this.$el.html( this.template({ labels: this.drawer.labels }) ); 224 this.$clearResults = this.$( '.clear-results' ); 225 this.$field = this.$( '.search-group-field' ); 226 this.$spinner = this.$el.append( '<span class="search-group-spinner spinner" />' ).find( '.spinner' ); 227 this.updateClearResultsVisibility(); 228 return this; 229 }, 230 231 clearResults: function() { 232 this.collection.reset(); 233 this.$field.val( '' ).trigger( 'input' ).focus(); 234 }, 235 236 search: function() { 237 var view = this; 238 239 this.$el.addClass( 'is-searching' ); 240 this.$spinner.addClass( 'is-active' ); 241 242 clearTimeout( this.timeout ); 243 this.timeout = setTimeout(function() { 244 view.drawer.search( view.$field.val() ) 245 .always(function() { 246 view.$el.removeClass( 'is-searching' ); 247 view.$spinner.removeClass( 'is-active' ); 248 }); 249 }, 300 ); 250 }, 251 252 updateClearResultsVisibility: function() { 253 this.$clearResults.toggleClass( 'is-visible', !! this.collection.length && '' !== this.$field.val() ); 254 } 255 }), 256 257 SearchResultsView: wp.Backbone.View.extend({ 258 tagName: 'div', 259 className: 'search-results', 260 261 initialize: function( options ) { 262 this.collection = options.collection; 263 this.drawer = options.drawer; 264 this.selection = options.selection; 265 266 this.listenTo( this.collection, 'reset', this.render ); 267 }, 268 269 render: function() { 270 this.$list = this.$el.html( '<ul />' ).find( 'ul' ); 271 this.$el.toggleClass( 'hide-type-label', 1 === this.drawer.postTypes.length ); 272 273 if ( this.collection.length ) { 274 this.collection.each( this.addItem, this ); 275 } else { 276 this.$el.empty(); 277 } 278 279 return this; 280 }, 281 282 addItem: function( model ) { 283 this.views.add( 'ul', new this.drawer.SearchResultView({ 284 drawer: this.drawer, 285 model: model, 286 selection: this.selection 287 })); 288 } 289 }), 290 291 SearchResultView: wp.Backbone.View.extend({ 292 tagName: 'li', 293 className: 'search-results-item', 294 template: wp.template( 'search-result' ), 295 296 events: { 297 'click': 'addItem' 298 }, 299 300 initialize: function( options ) { 301 this.drawer = options.drawer; 302 this.model = options.model; 303 this.selection = options.selection; 304 305 this.listenTo( this.selection, 'add remove reset', this.updateSelectedClass ); 306 }, 307 308 render: function() { 309 var data = _.extend( this.model.toJSON(), { 310 labels: this.drawer.labels 311 }); 312 313 this.$el.html( this.template( data ) ); 314 this.updateSelectedClass(); 315 316 return this; 317 }, 318 319 addItem: function() { 320 this.selection.add( this.model ); 321 }, 322 323 updateSelectedClass: function() { 324 this.$el.toggleClass( 'is-selected', !! this.selection.get( this.model.id ) ); 325 } 326 }) 327 }); 328 329 api.PostCollectionControl = api.Control.extend({ 330 ready: function() { 331 var control = this; 332 333 this.posts = new api.PostsCollection( this.params.posts ); 334 delete this.params.posts; 335 336 this.drawer = new api.PostSearchDrawer( this.id, { 337 control: this.id, 338 labels: _.extend( this.params.labels, { 339 customizeAction: this.params.labels.addPosts, 340 title: this.params.label 341 }), 342 postTypes: this.params.postTypes, 343 searchNonce: this.params.searchNonce, 344 selection: this.posts 345 }); 346 api.drawer.add( this.id, this.drawer ); 347 348 // Update the setting when the post collection is modified. 349 this.posts.on( 'add remove reset sort', function() { 350 var ids = this.posts.pluck( 'id' ); 351 352 if ( this.setting() !== ids ) { 353 this.setting.set( ids ); 354 } 355 }, this ); 356 357 if ( this.params.includeFrontPage ) { 358 // Add the front page when it changes. 359 api( 'page_on_front', function( setting ) { 360 setting.bind( _.bind( control.onPageOnFrontChange, control ) ); 361 }); 362 } 363 364 this.view = new wp.Backbone.View({ 365 el: this.container 366 }); 367 368 this.view.views.add([ 369 new this.ListView({ 370 collection: this.posts, 371 control: this 372 }), 373 new this.AddNewItemButtonView({ 374 control: this 375 }) 376 ]); 377 }, 378 379 onPageOnFrontChange: function( value ) { 380 var id = parseInt( value, 10 ), 381 posts = this.posts.toJSON(), 382 pageOnFrontControl = api.control( 'page_on_front' ); 383 384 if ( id > 1 && ! this.posts.findWhere({ id: id }) ) { 385 posts.unshift({ 386 id: id, 387 // @todo Find a better way to grab this title. 388 title: pageOnFrontControl.container.find( 'option:selected' ).text() 389 }); 390 } 391 392 // Remove the previous front page if it was the only post in the list. 393 if ( 2 === posts.length ) { 394 posts = posts.shift(); 395 } 396 397 // Reset the collection to re-render the view. 398 this.posts.reset( posts ); 399 }, 400 401 AddNewItemButtonView: wp.Backbone.View.extend({ 402 className: 'add-new-item button button-secondary alignright', 403 tagName: 'button', 404 405 events: { 406 click: 'toggleDrawer' 407 }, 408 409 initialize: function( options ) { 410 this.control = options.control; 411 }, 412 413 render: function() { 414 this.$el.text( this.control.params.labels.addPosts ); 415 return this; 416 }, 417 418 toggleDrawer: function( e ) { 419 e.preventDefault(); 420 this.control.drawer.toggle(); 421 } 422 }), 423 424 ListView: wp.Backbone.View.extend({ 425 className: 'wp-items-list', 426 tagName: 'ol', 427 428 initialize: function( options ) { 429 var view = this; 430 431 this.control = options.control; 432 433 this.listenTo( this.collection, 'add', this.addItem ); 434 this.listenTo( this.collection, 'add remove', this.updateOrder ); 435 this.listenTo( this.collection, 'reset', this.render ); 436 }, 437 438 render: function() { 439 this.$el.empty(); 440 this.collection.each( this.addItem, this ); 441 this.initializeSortable(); 442 return this; 443 }, 444 445 initializeSortable: function() { 446 this.$el.sortable({ 447 axis: 'y', 448 delay: 150, 449 forceHelperSize: true, 450 forcePlaceholderSize: true, 451 opacity: 0.6, 452 start: function( e, ui ) { 453 ui.placeholder.css( 'visibility', 'visible' ); 454 }, 455 update: _.bind(function() { 456 this.updateOrder(); 457 }, this ) 458 }); 459 }, 460 461 addItem: function( item ) { 462 var itemView = new this.control.ItemView({ 463 control: this.control, 464 model: item, 465 parent: this 466 }); 467 468 this.$el.append( itemView.render().el ); 469 }, 470 471 moveDown: function( model ) { 472 var index = this.collection.indexOf( model ), 473 $items = this.$el.children(); 474 475 if ( index < this.collection.length - 1 ) { 476 $items.eq( index ).insertAfter( $items.eq( index + 1 ) ); 477 this.updateOrder(); 478 wp.a11y.speak( this.control.params.labels.movedDown ); 479 } 480 }, 481 482 moveUp: function( model ) { 483 var index = this.collection.indexOf( model ), 484 $items = this.$el.children(); 485 486 if ( index > 0 ) { 487 $items.eq( index ).insertBefore( $items.eq( index - 1 ) ); 488 this.updateOrder(); 489 wp.a11y.speak( this.control.params.labels.movedUp ); 490 } 491 }, 492 493 updateOrder: function() { 494 _.each( this.$el.children(), function( item, index ) { 495 var id = $( item ).data( 'post-id' ); 496 this.collection.get( id ).set( 'sortableOrder', index ); 497 }, this ); 498 499 this.collection.sort(); 500 } 501 }), 502 503 ItemView: wp.Backbone.View.extend({ 504 tagName: 'li', 505 className: 'wp-item', 506 template: wp.template( 'wp-item' ), 507 508 events: { 509 'click .wp-item-delete': 'destroy', 510 'click .move-item-up': 'moveUp', 511 'click .move-item-down': 'moveDown' 512 }, 513 514 initialize: function( options ) { 515 this.control = options.control; 516 this.parent = options.parent; 517 this.listenTo( this.model, 'destroy', this.remove ); 518 }, 519 520 render: function() { 521 var isFrontPage = this.model.get( 'id' ) == api( 'page_on_front' )(), 522 canDelete = ! this.control.params.includeFrontPage || ! isFrontPage, 523 data = _.extend( this.model.toJSON(), { 524 labels: this.control.params.labels, 525 includeFrontPage: this.control.params.includeFrontPage, 526 showDeleteButton: canDelete 527 }); 528 529 this.$el.html( this.template( data ) ); 530 this.$el.data( 'post-id', this.model.get( 'id' ) ); 531 532 if ( ! canDelete ) { 533 this.$el.addClass( 'hide-delete' ); 534 } 535 536 return this; 537 }, 538 539 moveDown: function( e ) { 540 e.preventDefault(); 541 this.parent.moveDown( this.model ); 542 }, 543 544 moveUp: function( e ) { 545 e.preventDefault(); 546 this.parent.moveUp( this.model ); 547 }, 548 549 /** 550 * Destroy the view's model. 551 * 552 * Avoid syncing to the server by triggering an event instead of 553 * calling destroy() directly on the model. 554 */ 555 destroy: function() { 556 this.model.trigger( 'destroy', this.model ); 557 }, 558 559 remove: function() { 560 this.$el.remove(); 561 } 562 }) 563 }); 564 565 /** 566 * Toggle the front page sections control based on front page settings. 567 */ 568 function toggleFrontPageSectionsControl() { 569 var controlId = 'front_page_sections', 570 showOnFront = api( 'show_on_front' )(), 571 pageOnFront = api( 'page_on_front' )(), 572 isVisible = 'page' === showOnFront && parseInt( pageOnFront ) > 0; 573 574 if ( api.control.has( controlId ) ) { 575 api.control( controlId ).container.toggle( isVisible ); 576 } 577 } 578 579 /** 580 * Create the collection for Drawers. 581 */ 582 api.drawer = new api.Values({ defaultConstructor: api.Drawer }); 583 584 /** 585 * Extends wp.customize.controlConstructor with control constructor for 586 * post_collection. 587 */ 588 $.extend( api.controlConstructor, { 589 post_collection: api.PostCollectionControl 590 }); 591 592 /** 593 * Bind events to toggle visibilty of the front page sections control. 594 */ 595 api.bind( 'ready', function() { 596 api( 'show_on_front' ).bind( toggleFrontPageSectionsControl ); 597 api( 'page_on_front' ).bind( toggleFrontPageSectionsControl ); 598 api.section( 'static_front_page' ).expanded.bind( toggleFrontPageSectionsControl ); 599 }); 600 601 })( window.wp, jQuery ); -
src/wp-includes/canonical.php
655 655 exit; 656 656 } 657 657 } 658 659 /** 660 * Redirect front page section permalinks to the 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' ) ), 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 }}</span></h4> 144 145 <# if ( data.showDeleteButton ) { #> 146 <button type="button" class="wp-item-delete button-link"> 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-drawer-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.customizeAction }}' ); 167 ?> 168 </span> 169 {{ data.title }} 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 }}</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 $data = array(); 200 $value = $this->value(); 201 $post_ids = array_filter( 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( $post_ids ) ) { 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
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' ), 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 25 // Make the request 26 try { 27 $this->_handleAjax( 'find_posts' ); 28 } catch ( WPAjaxDieContinueException $e ) { 29 unset( $e ); 30 } 31 32 // Get the response. 33 $response = json_decode( $this->_last_response, true ); 34 35 $this->assertThat( $response['data'], $this->stringContains( $page->post_title ) ); 36 $this->assertThat( $response['data'], $this->stringContains( $post->post_title ) ); 37 } 38 39 public function test_wp_ajax_find_posts_does_not_return_attachments() { 40 41 $this->_setRole( 'administrator' ); 42 43 $attachment_id = $this->front_page_section = self::factory()->post->create(array( 44 'post_type' => 'attachment', 45 ) ); 46 $attachment = get_post( $attachment_id ); 47 48 // Set up a default request 49 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 50 51 // Make the request 52 try { 53 $this->_handleAjax( 'find_posts' ); 54 } catch ( WPAjaxDieContinueException $e ) { 55 unset( $e ); 56 } 57 58 // Get the response. 59 $response = json_decode( $this->_last_response, true ); 60 61 $this->assertThat( $response['data'], $this->logicalNot( $this->stringContains( $attachment->post_title ) ) ); 62 } 63 64 public function test_wp_ajax_find_posts_searches() { 65 66 $this->_setRole( 'administrator' ); 67 68 $post_id = $this->front_page_section = self::factory()->post->create(); 69 $post = get_post( $post_id ); 70 71 $post2_id = $this->front_page_section = self::factory()->post->create(); 72 $post2 = get_post( $post2_id ); 73 74 // Set up a default request 75 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 76 $_POST['ps'] = $post->post_title; 77 78 // Make the request 79 try { 80 $this->_handleAjax( 'find_posts' ); 81 } catch ( WPAjaxDieContinueException $e ) { 82 unset( $e ); 83 } 84 85 // Get the response. 86 $response = json_decode( $this->_last_response, true ); 87 88 $this->assertThat( $response['data'], $this->stringContains( $post->post_title ) ); 89 $this->assertThat( $response['data'], $this->logicalNot( $this->stringContains( $post2->post_title ) ) ); 90 } 91 92 public function test_wp_ajax_find_posts_filters_by_status() { 93 94 $this->_setRole( 'administrator' ); 95 96 $draft_id = $this->front_page_section = self::factory()->post->create( array( 97 'post_status' => 'draft', 98 ) ); 99 $draft = get_post( $draft_id ); 100 101 $post2_id = $this->front_page_section = self::factory()->post->create(); 102 $post2 = get_post( $post2_id ); 103 104 // Set up a default request 105 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 106 $_POST['status'] = 'draft'; 107 108 // Make the request 109 try { 110 $this->_handleAjax( 'find_posts' ); 111 } catch ( WPAjaxDieContinueException $e ) { 112 unset( $e ); 113 } 114 115 // Get the response. 116 $response = json_decode( $this->_last_response, true ); 117 118 $this->assertThat( $response['data'], $this->stringContains( $draft->post_title ) ); 119 $this->assertThat( $response['data'], $this->logicalNot( $this->stringContains( $post2->post_title ) ) ); 120 } 121 122 public function test_wp_ajax_find_posts_returns_json() { 123 124 $this->_setRole( 'administrator' ); 125 126 $post_id = $this->front_page_section = self::factory()->post->create(); 127 $post = get_post( $post_id ); 128 129 // Set up a default request 130 $_POST['_ajax_nonce'] = wp_create_nonce( 'find-posts' ); 131 $_POST['format'] = 'json'; 132 133 // Make the request 134 try { 135 $this->_handleAjax( 'find_posts' ); 136 } catch ( WPAjaxDieContinueException $e ) { 137 unset( $e ); 138 } 139 140 // Get the response. 141 $response = json_decode( $this->_last_response, true ); 142 143 $post_type = get_post_type_object( $post->post_type ); 144 $expected = array( 145 'id' => $post->ID, 146 'title' => $post->post_title, 147 'type' => $post_type->labels->singular_name, 148 ); 149 150 $this->assertContains( $expected, $response['data'] ); 151 } 152 } -
tests/phpunit/tests/query/frontPageSections.php
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