Ticket #31303: 31303.diff
| File 31303.diff, 25.4 KB (added by , 11 years ago) |
|---|
-
src/wp-admin/css/customize-controls.css
831 831 float: right; 832 832 } 833 833 834 /** 835 * Themes 836 */ 837 @-webkit-keyframes customize-reload { 838 0% { opacity: 0; } 839 100% { opacity: 1; } 840 } 834 841 842 @-moz-keyframes customize-reload { 843 0% { opacity: 0; } 844 100% { opacity: 1; } 845 } 846 847 @keyframes customize-reload { 848 0% { opacity: 0; } 849 100% { opacity: 1; } 850 } 851 852 /* #customize-container is reused from customize-loader.js, hence the naming. */ 853 .wp-customizer.customize-loading #customize-container { 854 display: block; 855 -webkit-animation: customize-reload .75s; /* Can't use `transition` because `display` changes here. */ 856 -moz-animation: customize-reload .75s; 857 animation: customize-reload .75s; 858 } 859 860 .customize-themes-panel { 861 display: none; 862 padding: 0 8px; 863 background: #f1f1f1; 864 box-sizing: border-box; 865 -webkit-box-sizing: border-box; 866 -moz-box-sizing: border-box; 867 } 868 869 .control-section.open .customize-themes-panel { 870 display: block; 871 } 872 873 #customize-theme-controls .customize-themes-panel .accordion-section-content { 874 background: transparent; 875 display: block; 876 } 877 878 .customize-control.customize-control-theme { 879 margin-bottom: 8px; 880 } 881 882 .wp-customizer .theme-browser .themes { 883 padding-bottom: 8px; 884 } 885 886 .wp-customizer .theme-browser .theme { 887 margin: 0; 888 width: 100%; 889 } 890 891 .wp-customizer .theme-browser .theme .theme-actions { 892 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 893 opacity: 1; 894 } 895 896 #customize-controls h3.theme-name { 897 font-size: 15px; 898 } 899 900 .wp-customizer .theme-browser .theme.active .theme-name { 901 padding-right: 15px; 902 } 903 904 .wp-customizer #themes-filter { 905 width: 100%; 906 } 907 908 /* Panel-like behavior */ 909 #accordion-section-themes .accordion-section-title:after { 910 content: "\f148"; 911 } 912 913 .rtl #accordion-section-themes .accordion-section-title:after { 914 -webkit-transform: rotate(180deg); 915 -ms-transform: rotate(180deg); 916 transform: rotate(180deg); 917 } 918 919 #customize-theme-controls .control-section.current-panel > h3.accordion-section-title { 920 left: 0; 921 } 922 923 .customize-themes-panel.control-panel-content { 924 position: absolute; 925 left: -100%; 926 top: 0; 927 width: 100%; 928 border-top: 1px solid #ddd; 929 } 930 931 .in-themes-panel #customize-info, 932 .in-themes-panel #customize-theme-controls > ul > .accordion-section { 933 left: 100%; 934 } 935 936 .themes-panel-back:before { 937 top: 13px; 938 left: 14px; 939 } 940 941 .in-themes-panel .themes-panel-back { 942 left: 0; 943 } 944 945 .in-sub-panel .themes-panel-back { 946 display: none; 947 } 948 949 .control-panel-back.themes-panel-back:before { 950 content: "\f345"; 951 } 952 953 .rtl .control-panel-back.themes-panel-back:before { 954 content: "\f341"; 955 } 956 957 /* Details View */ 958 .wp-customizer .theme-overlay { 959 display: none; 960 } 961 962 .wp-customizer.modal-open .theme-overlay { 963 position: fixed; 964 left: 0; 965 top: 0; 966 right: 0; 967 bottom: 0; 968 z-index: 109; 969 } 970 971 .wp-customizer .theme-overlay .theme-backdrop { 972 background: rgba( 238, 238, 238, 0.75 ); 973 position: fixed; 974 z-index: 110; 975 } 976 977 .wp-customizer .theme-overlay .theme-wrap { 978 left: 90px; 979 right: 90px; 980 top: 45px; 981 bottom: 45px; 982 z-index: 120; 983 max-width: 1740px; /* To ensure that theme screenshots are not displayed larger than 880px wide. */ 984 } 985 986 .wp-customizer .theme-overlay .theme-actions { 987 text-align: right; /* Because there's only one action, match the pattern of media modals and right-align the action. */ 988 } 989 990 .modal-open .in-themes-panel #customize-controls .wp-full-overlay-sidebar-content { 991 overflow: visible; /* Prevent the top-level Customizer controls from becoming visible when elements on the right of the details modal are focused. 992 } 993 994 /* Small Screens */ 995 @media (max-width:850px), (max-height:472px) { 996 .wp-customizer .theme-overlay .theme-wrap { 997 left: 0; 998 right: 0; 999 top: 0; 1000 bottom: 0; 1001 } 1002 } 1003 1004 835 1005 /** Handle cheaters. */ 836 1006 body.cheatin { 837 1007 font-size: medium; -
src/wp-admin/includes/theme.php
486 486 $prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes ); 487 487 return array_values( $prepared_themes ); 488 488 } 489 490 /** 491 * Print JS templates for the theme-browsing UI in the Customizer. 492 * 493 * @since 4.2.0 494 */ 495 function customize_themes_print_templates() { 496 ?> 497 <script type="text/html" id="tmpl-customize-themes-details-view"> 498 <div class="theme-backdrop"></div> 499 <div class="theme-wrap"> 500 <div class="theme-header"> 501 <button type="button" class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous theme' ); ?></span></button> 502 <button type="button" class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next theme' ); ?></span></button> 503 <button type="button" class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog' ); ?></span></button> 504 </div> 505 <div class="theme-about"> 506 <div class="theme-screenshots"> 507 <# if ( data.screenshot[0] ) { #> 508 <div class="screenshot"><img src="{{ data.screenshot[0] }}" alt="" /></div> 509 <# } else { #> 510 <div class="screenshot blank"></div> 511 <# } #> 512 </div> 513 514 <div class="theme-info"> 515 <# if ( data.active ) { #> 516 <span class="current-label"><?php _e( 'Current Theme' ); ?></span> 517 <# } #> 518 <h3 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h3> 519 <h4 class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></h4> 520 <p class="theme-description">{{{ data.description }}}</p> 521 522 <# if ( data.parent ) { #> 523 <p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p> 524 <# } #> 525 526 <# if ( data.tags ) { #> 527 <p class="theme-tags"><span><?php _e( 'Tags:' ); ?></span> {{ data.tags }}</p> 528 <# } #> 529 </div> 530 </div> 531 532 <div class="theme-actions"> 533 <# if ( ! data.active ) { #> 534 <div class="inactive-theme"> 535 <a href="<?php echo add_query_arg( 'theme', '{{ data.id }}', remove_query_arg( 'theme' ) ); ?>" target="_top" class="button button-primary"><?php _e( 'Live Preview' ); ?></a> 536 </div> 537 <# } #> 538 </div> 539 </div> 540 </script> 541 <?php 542 } 543 add_action( 'customize_controls_print_footer_scripts', 'customize_themes_print_templates' ); -
src/wp-admin/js/customize-controls.js
521 521 }); 522 522 523 523 /** 524 * wp.customize.ThemesSection 525 * 526 * Custom section for themes that functions similarly to a backwards panel, 527 * and also handles the theme-details view rendering and navigation. 528 * 529 * @constructor 530 * @augments wp.customize.Section 531 * @augments wp.customize.Container 532 */ 533 api.ThemesSection = api.Section.extend({ 534 currentTheme: '', 535 overlay: '', 536 template: '', 537 538 /** 539 * @since 4.2.0 540 */ 541 ready: function () { 542 var section = this; 543 section.overlay = section.container.find( '.theme-overlay' ); 544 section.template = wp.template( 'customize-themes-details-view' ); 545 546 // Bind global keyboard events. 547 $( 'body' ).on( 'keyup', function( event ) { 548 if ( ! section.overlay.find( '.theme-wrap' ).is( ':visible' ) ) { 549 return; 550 } 551 552 // Pressing the right arrow key fires a theme:next event 553 if ( 39 === event.keyCode ) { 554 section.nextTheme(); 555 } 556 557 // Pressing the left arrow key fires a theme:previous event 558 if ( 37 === event.keyCode ) { 559 section.previousTheme(); 560 } 561 562 // Pressing the escape key fires a theme:collapse event 563 if ( 27 === event.keyCode ) { 564 section.closeDetails(); 565 } 566 }); 567 }, 568 569 /** 570 * @since 4.2.0 571 */ 572 attachEvents: function () { 573 var meta, section = this; 574 575 // Expand/Collapse section/panel. 576 section.container.find( '.accordion-section-title' ).on( 'click keydown', function( event ) { 577 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 578 return; 579 } 580 event.preventDefault(); // Keep this AFTER the key filter above 581 582 if ( section.expanded() ) { 583 section.collapse(); 584 } else { 585 section.expand(); 586 } 587 }); 588 589 section.container.find( '.themes-panel-back' ).on( 'click keydown', function( event ) { 590 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 591 return; 592 } 593 594 event.preventDefault(); // Keep this AFTER the key filter above 595 596 section.collapse(); 597 }); 598 599 // Theme navigation in details view. 600 section.container.on( 'click keydown', '.left', function( event ) { 601 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 602 return; 603 } 604 605 event.preventDefault(); // Keep this AFTER the key filter above 606 607 section.previousTheme(); 608 }); 609 610 section.container.on( 'click keydown', '.right', function( event ) { 611 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 612 return; 613 } 614 615 event.preventDefault(); // Keep this AFTER the key filter above 616 617 section.nextTheme(); 618 }); 619 620 section.container.on( 'click keydown', '.theme-backdrop, .close', function( event ) { 621 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 622 return; 623 } 624 625 event.preventDefault(); // Keep this AFTER the key filter above 626 627 section.closeDetails(); 628 }); 629 630 section.container.on( 'click keydown', '.theme-actions .button', function( event ) { 631 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 632 return; 633 } 634 635 $( 'body' ).addClass( 'customize-loading' ); // @todo if they get a `confirm()`, remove the class if they stay (core patch). 636 }); 637 638 section.container.on( 'input', '#themes-filter', function( event ) { 639 var term = event.currentTarget.value.toLowerCase().trim().replace( '-', ' ' ), 640 controls = section.controls(); 641 controls.pop(); // Remove the last control (the add-new control). 642 _.each( controls, function( control ) { 643 control.filter( term ); 644 }); 645 // Update theme count. Note that the add-theme tile is a div.customize-control. 646 count = section.container.find( 'li.customize-control:visible' ).length; 647 section.container.find( '.theme-count' ).text( count ); 648 }); 649 }, 650 651 /** 652 * Update UI to reflect expanded state 653 * 654 * @since 4.2.0 655 * 656 * @param {Boolean} expanded 657 * @param {Object} args 658 * @param {Boolean} args.unchanged 659 * @param {Callback} args.completeCallback 660 */ 661 onChangeExpanded: function ( expanded, args ) { 662 663 // Immediately call the complete callback if there were no changes 664 if ( args.unchanged ) { 665 if ( args.completeCallback ) { 666 args.completeCallback(); 667 } 668 return; 669 } 670 671 // Note: there is a second argument 'args' passed 672 var position, scroll, 673 panel = this, 674 section = panel.container.closest( '.accordion-section' ), 675 overlay = section.closest( '.wp-full-overlay' ), 676 container = section.closest( '.accordion-container' ), 677 siblings = container.find( '.open' ), 678 topPanel = overlay.find( '#customize-theme-controls > ul > .accordion-section > .accordion-section-title' ).add( '#customize-info > .accordion-section-title' ), 679 backBtn = overlay.find( '.themes-panel-back' ), 680 panelTitle = section.find( '.accordion-section-title' ).first(), 681 content = section.find( '.control-panel-content' ); 682 683 if ( expanded ) { 684 685 // Collapse any sibling sections/panels 686 api.section.each( function ( otherSection ) { 687 if ( otherSection !== panel ) { 688 otherSection.collapse( { duration: args.duration } ); 689 } 690 }); 691 api.panel.each( function ( otherPanel ) { 692 if ( panel !== otherPanel ) { 693 otherPanel.collapse( { duration: 0 } ); 694 } 695 }); 696 697 content.show( 0, function() { 698 position = content.offset().top; 699 scroll = container.scrollTop(); 700 content.css( 'margin-top', ( 45 - position - scroll ) ); 701 section.addClass( 'current-panel' ); 702 overlay.addClass( 'in-themes-panel' ); 703 container.scrollTop( 0 ); 704 if ( args.completeCallback ) { 705 args.completeCallback(); 706 } 707 } ); 708 topPanel.attr( 'tabindex', '-1' ); 709 backBtn.attr( 'tabindex', '0' ); 710 backBtn.focus(); 711 } else { 712 siblings.removeClass( 'open' ); 713 section.removeClass( 'current-panel' ); 714 overlay.removeClass( 'in-themes-panel' ); 715 content.delay( 180 ).hide( 0, function() { 716 content.css( 'margin-top', 'inherit' ); // Reset 717 if ( args.completeCallback ) { 718 args.completeCallback(); 719 } 720 } ); 721 topPanel.attr( 'tabindex', '0' ); 722 backBtn.attr( 'tabindex', '-1' ); 723 panelTitle.focus(); 724 container.scrollTop( 0 ); 725 } 726 }, 727 728 /** 729 * Advance the modal to the next theme. 730 * 731 * @since 4.2.0 732 */ 733 nextTheme: function () { 734 var section = this; 735 if ( section.getNextTheme() ) { 736 section.showDetails( section.getNextTheme(), function() { 737 section.overlay.find( '.right' ).focus(); 738 } ); 739 } 740 }, 741 742 /** 743 * Get the next theme model. 744 * 745 * @since 4.2.0 746 */ 747 getNextTheme: function () { 748 var control, next; 749 control = api.control( 'theme_' + this.currentTheme ); 750 next = control.container.next( 'li.customize-control-theme' ); 751 if ( ! next.length ) { 752 return false; 753 } 754 next = next[0].id.replace( 'customize-control-', '' ); 755 control = api.control( next ); 756 757 return control.params.theme; 758 }, 759 760 /** 761 * Advance the modal to the previous theme. 762 * 763 * @since 4.2.0 764 */ 765 previousTheme: function () { 766 var section = this; 767 if ( section.getPreviousTheme() ) { 768 section.showDetails( section.getPreviousTheme(), function() { 769 section.overlay.find( '.left' ).focus(); 770 } ); 771 } 772 }, 773 774 /** 775 * Get the previous theme model. 776 * 777 * @since 4.2.0 778 */ 779 getPreviousTheme: function () { 780 var control, previous; 781 control = api.control( 'theme_' + this.currentTheme ); 782 previous = control.container.prev( 'li.customize-control-theme' ); 783 if ( ! previous.length ) { 784 return false; 785 } 786 previous = previous[0].id.replace( 'customize-control-', '' ); 787 control = api.control( previous ); 788 789 return control.params.theme; 790 }, 791 792 /** 793 * Disable buttons when we're viewing the first or last theme. 794 * 795 * @since 4.2.0 796 */ 797 updateLimits: function () { 798 if ( ! this.getNextTheme() ) { 799 this.overlay.find( '.right' ).addClass( 'disabled' ); 800 } 801 if ( ! this.getPreviousTheme() ) { 802 this.overlay.find( '.left' ).addClass( 'disabled' ); 803 } 804 }, 805 806 /** 807 * Render & show the theme details for a given theme model. 808 * 809 * @since 4.2.0 810 * 811 * @param {Object} theme 812 */ 813 showDetails: function ( theme, callback ) { 814 var section = this; 815 callback = callback || function(){}; 816 section.currentTheme = theme.id; 817 section.overlay.html( section.template( theme ) ) 818 .fadeIn( 'fast' ) 819 .focus(); 820 $( 'body' ).addClass( 'modal-open' ); 821 section.containFocus( section.overlay ); 822 section.updateLimits(); 823 callback(); 824 }, 825 826 /** 827 * Close the theme details modal. 828 * 829 * @since 4.2.0 830 */ 831 closeDetails: function ( theme ) { 832 $( 'body' ).removeClass( 'modal-open' ); 833 this.overlay.fadeOut( 'fast' ); 834 api.control( 'theme_' + this.currentTheme ).focus(); 835 }, 836 837 /** 838 * Keep tab focus within the theme details modal. 839 * 840 * @since 4.2.0 841 */ 842 containFocus: function( el ) { 843 var tabbables; 844 845 el.on( 'keydown', function( event ) { 846 847 // Return if it's not the tab key 848 // When navigating with prev/next focus is already handled 849 if ( 9 !== event.keyCode ) { 850 return; 851 } 852 853 // uses jQuery UI to get the tabbable elements 854 tabbables = $( ':tabbable', el ); 855 856 // Keep focus within the overlay 857 if ( tabbables.last()[0] === event.target && ! event.shiftKey ) { 858 tabbables.first().focus(); 859 return false; 860 } else if ( tabbables.first()[0] === event.target && event.shiftKey ) { 861 tabbables.last().focus(); 862 return false; 863 } 864 }); 865 } 866 }); 867 868 /** 524 869 * @since 4.1.0 525 870 * 526 871 * @class … … 1409 1754 1410 1755 }); 1411 1756 1757 /** 1758 * wp.customize.ThemeControl 1759 * 1760 * @constructor 1761 * @augments wp.customize.Control 1762 * @augments wp.customize.Class 1763 */ 1764 api.ThemeControl = api.Control.extend({ 1765 1766 /** 1767 * @since 4.2.0 1768 */ 1769 ready: function() { 1770 var control = this; 1771 1772 // Bind details view trigger. 1773 control.container.on( 'click keydown', '.theme', function( event ) { 1774 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1775 return; 1776 } 1777 1778 if ( 'button' === event.target.className ) { 1779 return; 1780 } 1781 1782 api.section( control.section() ).showDetails( control.params.theme ); 1783 }); 1784 1785 control.container.on( 'click keydown', '.theme-actions .button', function( event ) { 1786 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1787 return; 1788 } 1789 1790 $( 'body' ).addClass( 'customize-loading' ); 1791 }); 1792 }, 1793 1794 /** 1795 * Show or hide the theme based on the presence of the term in the title, description, and author. 1796 * 1797 * @since 4.2.0 1798 */ 1799 filter: function( term ) { 1800 var control = this, 1801 haystack = control.params.theme.name + ' ' 1802 + control.params.theme.description + ' ' 1803 + control.params.theme.tags + ' ' 1804 + control.params.theme.author; 1805 haystack = haystack.toLowerCase().replace( '-', ' ' ); 1806 if ( -1 !== haystack.search( term ) ) { 1807 control.activate(); 1808 } else { 1809 control.deactivate(); 1810 } 1811 } 1812 }); 1813 1412 1814 // Change objects contained within the main customize object to Settings. 1413 1815 api.defaultConstructor = api.Setting; 1414 1816 … … 1853 2255 }); 1854 2256 1855 2257 api.controlConstructor = { 1856 color: api.ColorControl, 1857 upload: api.UploadControl, 1858 image: api.ImageControl, 1859 header: api.HeaderControl, 1860 background: api.BackgroundControl 2258 color: api.ColorControl, 2259 upload: api.UploadControl, 2260 image: api.ImageControl, 2261 header: api.HeaderControl, 2262 background: api.BackgroundControl, 2263 theme: api.ThemeControl 1861 2264 }; 1862 2265 api.panelConstructor = {}; 1863 api.sectionConstructor = {}; 2266 api.sectionConstructor = { 2267 themes: api.ThemesSection 2268 }; 1864 2269 1865 2270 $( function() { 1866 2271 api.settings = window._wpCustomizeSettings; -
src/wp-includes/class-wp-customize-control.php
1101 1101 } 1102 1102 1103 1103 /** 1104 * Customize Theme Control Class 1105 * 1106 * @package WordPress 1107 * @subpackage Customize 1108 * @since 4.2.0 1109 */ 1110 class WP_Customize_Theme_Control extends WP_Customize_Control { 1111 1112 public $type = 'theme'; 1113 public $theme; 1114 1115 /** 1116 * Refresh the parameters passed to the JavaScript via JSON. 1117 * 1118 * @since 4.2.0 1119 * @uses WP_Customize_Control::to_json() 1120 */ 1121 public function to_json() { 1122 parent::to_json(); 1123 $this->json['theme'] = $this->theme; 1124 } 1125 1126 /** 1127 * Don't render the control content from PHP, as it's rendered via JS on load. 1128 * 1129 * @since 4.2.0 1130 */ 1131 public function render_content() {} 1132 1133 /** 1134 * Render a JS template for theme display. 1135 * 1136 * @since 4.2.0 1137 */ 1138 public function content_template() { 1139 ?> 1140 <div class="theme<# if ( data.theme.active ) { #> active<# } #>" tabindex="0" aria-describedby="{{ data.theme.id }}-action {{ data.theme.id }}-name"> 1141 <# if ( data.theme.screenshot[0] ) { #> 1142 <div class="theme-screenshot"> 1143 <img src="{{ data.theme.screenshot[0] }}" alt="" /> 1144 </div> 1145 <# } else { #> 1146 <div class="theme-screenshot blank"></div> 1147 <# } #> 1148 <span class="more-details" id="{{ data.theme.id }}-action"><?php _e( 'Theme Details' ); ?></span> 1149 <div class="theme-author"><?php printf( __( 'By %s' ), '{{ data.theme.author }}' ); ?></div> 1150 1151 <# if ( data.theme.active ) { #> 1152 <h3 class="theme-name" id="{{ data.theme.id }}-name"><span><?php _ex( 'Previewing:', 'theme' ); ?></span> {{ data.theme.name }}</h3> 1153 <# } else { #> 1154 <h3 class="theme-name" id="{{ data.theme.id }}-name">{{ data.theme.name }}</h3> 1155 <# } #> 1156 1157 <# if ( ! data.theme.active ) { #> 1158 <div class="theme-actions"> 1159 <a class="button" href="<?php echo add_query_arg( 'theme', '{{ data.theme.id }}', remove_query_arg( 'theme' ) ); ?>" target="_top"><?php _e( 'Live Preview' ); ?></a> 1160 </div> 1161 <# } #> 1162 </div> 1163 <?php 1164 } 1165 } 1166 1167 /** 1168 * Customize New Theme Control Class 1169 * 1170 * @package WordPress 1171 * @subpackage Customize 1172 * @since 4.2.0 1173 */ 1174 class WP_Customize_New_Theme_Control extends WP_Customize_Control { 1175 1176 /** 1177 * Render the new control. 1178 * 1179 * @since 4.2.0 1180 */ 1181 public function render() { 1182 if ( is_multisite() || ! current_user_can( 'install_themes') ) { 1183 return; 1184 } 1185 ?> 1186 <div class="theme add-new-theme"> 1187 <a href="<?php echo admin_url( 'theme-install.php' ); ?>" target="_top"> 1188 <div class="theme-screenshot"> 1189 <span></span> 1190 </div> 1191 <h3 class="theme-name"><?php _e( 'Add New Theme' ); ?></h3> 1192 </a> 1193 </div> 1194 <?php 1195 } 1196 } 1197 1198 /** 1104 1199 * Widget Area Customize Control Class 1105 1200 * 1106 1201 * @since 3.9.0 -
src/wp-includes/class-wp-customize-manager.php
1110 1110 $this->register_control_type( 'WP_Customize_Upload_Control' ); 1111 1111 $this->register_control_type( 'WP_Customize_Image_Control' ); 1112 1112 $this->register_control_type( 'WP_Customize_Background_Image_Control' ); 1113 $this->register_control_type( 'WP_Customize_Theme_Control' ); 1113 1114 1115 /* Themes */ 1116 1117 $this->add_section( new WP_Customize_Themes_Section( $this, 'themes', array( 1118 'title' => sprintf( __( 'Theme: %s' ), $this->theme()->display('Name') ), 1119 'capability' => 'switch_themes', 1120 'priority' => 0, 1121 ) ) ); 1122 1123 // Themes Setting (unused - the theme is considerably more fundamental to the Customizer experience). 1124 $this->add_setting( new WP_Customize_Filter_Setting( $this, 'active_theme', array( 1125 'capability' => 'switch_themes', 1126 ) ) ); 1127 1128 require_once( ABSPATH . 'wp-admin/includes/theme.php' ); 1129 1130 // Theme Controls. 1131 $themes = wp_prepare_themes_for_js(); 1132 foreach ( $themes as $theme ) { 1133 $theme_id = 'theme_' . $theme['id']; 1134 $this->add_control( new WP_Customize_Theme_Control( $this, $theme_id, array( 1135 'theme' => $theme, 1136 'section' => 'themes', 1137 'settings' => 'active_theme', 1138 ) ) ); 1139 } 1140 1141 $this->add_control( new WP_Customize_New_Theme_Control( $this, 'add_theme', array( 1142 'section' => 'themes', 1143 'settings' => 'active_theme', 1144 ) ) ); 1145 1114 1146 /* Site Title & Tagline */ 1115 1147 1116 1148 $this->add_section( 'title_tagline', array( -
src/wp-includes/class-wp-customize-section.php
312 312 } 313 313 314 314 /** 315 * Customize Themes Section Class. 316 * 317 * A UI container for theme controls, which behaves like a backwards Panel. 318 * 319 * @package WordPress 320 * @subpackage Customize 321 * @since 4.2.0 322 */ 323 class WP_Customize_Themes_Section extends WP_Customize_Section { 324 325 public $type = 'themes'; 326 327 /** 328 * Render the themes section, which behaves like a panel. 329 * 330 * @since 4.2.0 331 */ 332 protected function render() { 333 $classes = 'accordion-section control-section control-section-' . $this->type; 334 ?> 335 <li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>"> 336 <h3 class="accordion-section-title" tabindex="0"> 337 <?php echo esc_html( $this->title ); ?> 338 <span class="screen-reader-text"><?php _e( 'Press return or enter to expand' ); ?></span> 339 </h3> 340 <span class="control-panel-back themes-panel-back" tabindex="-1"><span class="screen-reader-text"><?php _e( 'Back' ); ?></span></span> 341 <div class="customize-themes-panel control-panel-content themes-php"> 342 <h2><?php esc_html_e( 'Themes' ); ?> 343 <span class="title-count theme-count"><?php echo count( $this->controls ) - 1; ?></span> 344 <?php if ( ! is_multisite() && current_user_can( 'install_themes' ) ) : ?> 345 <a href="<?php echo admin_url( 'theme-install.php' ); ?>" target="_top" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'Add new theme' ); ?></a> 346 <?php endif; ?> 347 </h2> 348 <div class="theme-overlay" tabindex="0" role="dialog" aria-label="<?php esc_attr_e( 'Theme details' ); ?>"></div> 349 <div id="customize-container"></div> 350 <?php if ( 6 < count( $this->controls ) ) : ?> 351 <p><label for="themes-filter"> 352 <span class="screen-reader-text"><?php _e( 'Search installed themes...' ); ?></span> 353 <input type="search" id="themes-filter" placeholder="<?php esc_attr_e( 'Search installed themes...' ); ?>" /> 354 </label></p> 355 <?php endif; ?> 356 <div class="theme-browser rendered"> 357 <ul class="themes accordion-section-content"> 358 </ul> 359 </div> 360 </div> 361 </li> 362 <?php } 363 } 364 365 /** 315 366 * Customizer section representing widget area (sidebar). 316 367 * 317 368 * @package WordPress