Changeset 41807
- Timestamp:
- 10/10/2017 07:08:51 AM (7 years ago)
- Location:
- trunk/src
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/customize-controls.js
r41803 r41807 1718 1718 }); 1719 1719 1720 // Filter-search all theme objects loaded in the section. 1721 section.container.on( 'input', '.wp-filter-search-themes', function( event ) { 1722 section.filterSearch( event.currentTarget ); 1723 }); 1724 1725 // Event listeners for remote wporg queries with user-entered terms. 1726 if ( 'wporg' === section.params.action ) { 1727 1720 if ( 'local' === section.params.filter_type ) { 1721 1722 // Filter-search all theme objects loaded in the section. 1723 section.container.on( 'input', '.wp-filter-search-themes', function( event ) { 1724 section.filterSearch( event.currentTarget.value ); 1725 }); 1726 1727 } else if ( 'remote' === section.params.filter_type ) { 1728 1729 // Event listeners for remote queries with user-entered terms. 1728 1730 // Search terms. 1729 1731 debounced = _.debounce( section.checkTerm, 500 ); // Wait until there is no input for 500 milliseconds to initiate a search. … … 1741 1743 section.checkTerm( section ); 1742 1744 }); 1743 1744 // Toggle feature filter sections. 1745 section.contentContainer.on( 'click', '.feature-filter-toggle', function( e ) {1746 $( e.currentTarget )1747 .toggleClass( 'open')1748 .attr( 'aria-expanded', function( i, attr ) {1749 return 'true' === attr ? 'false' : 'true';1750 })1751 .next( '.filter-drawer' ).slideToggle( 180, 'linear', function() {1752 if ( 0 === section.filtersHeight) {1753 section.filtersHeight = $( this ).height();1754 1755 // First time, so it's opened. 1756 section.contentContainer.find( '.themes' ).css( 'margin-top', section.filtersHeight + 76 );1757 }1758 } );1759 if ( $( e.currentTarget ).hasClass( 'open' ) ) {1760 section.contentContainer.find( '.themes' ).css( 'margin-top', section.filtersHeight + 76 );1761 } else {1762 section.contentContainer.find( '.themes' ).css( 'margin-top', 0 );1763 }1764 } );1765 } 1745 } 1746 1747 // Toggle feature filters. 1748 section.contentContainer.on( 'click', '.feature-filter-toggle', function( e ) { 1749 $( e.currentTarget ) 1750 .toggleClass( 'open' ) 1751 .attr( 'aria-expanded', function( i, attr ) { 1752 return 'true' === attr ? 'false' : 'true'; 1753 }) 1754 .next( '.filter-drawer' ).slideToggle( 180, 'linear', function() { 1755 if ( 0 === section.filtersHeight ) { 1756 section.filtersHeight = $( this ).height(); 1757 1758 // First time, so it's opened. 1759 section.contentContainer.find( '.themes' ).css( 'margin-top', section.filtersHeight + 76 ); 1760 } 1761 }); 1762 if ( $( e.currentTarget ).hasClass( 'open' ) ) { 1763 section.contentContainer.find( '.themes' ).css( 'margin-top', section.filtersHeight + 76 ); 1764 } else { 1765 section.contentContainer.find( '.themes' ).css( 'margin-top', 0 ); 1766 } 1767 }); 1766 1768 1767 1769 // Setup section cross-linking. … … 1807 1809 // Try to load controls if none are loaded yet. 1808 1810 if ( 0 === section.loaded ) { 1809 section.load Controls();1811 section.loadThemes(); 1810 1812 } 1811 1813 … … 1822 1824 1823 1825 // Directly initialize an empty remote search to avoid a race condition. 1824 if ( '' === searchTerm && '' !== section.term && ' installed' !== section.params.action) {1826 if ( '' === searchTerm && '' !== section.term && 'local' !== section.params.filter_type ) { 1825 1827 section.term = ''; 1826 1828 section.initializeNewQuery( section.term, section.tags ); 1827 1829 } else { 1828 section.checkTerm( section ); 1830 if ( 'remote' === section.params.filter_type ) { 1831 section.checkTerm( section ); 1832 } else if ( 'local' === section.params.filter_type ) { 1833 section.filterSearch( searchTerm ); 1834 } 1829 1835 } 1830 section.filterSearch( section.contentContainer.find( '.wp-filter-search' ).get( 0 ) );1831 1836 } 1832 1837 otherSection.collapse( { duration: args.duration } ); … … 1878 1883 * @returns {void} 1879 1884 */ 1880 load Controls: function() {1885 loadThemes: function() { 1881 1886 var section = this, params, page, request; 1882 1887 … … 1895 1900 }; 1896 1901 1897 // Add fields for wporg actions.1898 if ( ' wporg' === section.params.action) {1902 // Add fields for remote filtering. 1903 if ( 'remote' === section.params.filter_type ) { 1899 1904 params.search = section.term; 1900 1905 params.tags = section.tags; … … 1907 1912 request = wp.ajax.post( 'customize_load_themes', params ); 1908 1913 request.done(function( data ) { 1909 var themes = data.themes , newThemeControls;1914 var themes = data.themes; 1910 1915 1911 1916 // Stop and try again if the term changed while loading. … … 1920 1925 section.nextTags = ''; 1921 1926 section.loading = false; 1922 section.load Controls();1927 section.loadThemes(); 1923 1928 return; 1924 1929 } 1925 1930 1926 1931 if ( 0 !== themes.length ) { 1927 newThemeControls = []; 1928 1929 // Add controls for each theme. 1930 _.each( themes, function( theme ) { 1931 var themeControl = new api.controlConstructor.theme( section.params.action + '_theme_' + theme.id, { 1932 type: 'theme', 1933 section: section.params.id, 1934 theme: theme, 1935 priority: section.loaded + 1 1936 } ); 1937 1938 api.control.add( themeControl ); 1939 newThemeControls.push( themeControl ); 1940 section.loaded = section.loaded + 1; 1941 }); 1932 1933 section.loadControls( themes, page ); 1942 1934 1943 1935 if ( 1 === page ) { … … 1951 1943 } 1952 1944 }); 1953 if ( ' installed' !== section.params.action) {1945 if ( 'local' !== section.params.filter_type ) { 1954 1946 wp.a11y.speak( api.settings.l10n.themeSearchResults.replace( '%d', data.info.results ) ); 1955 1947 } 1956 } else {1957 Array.prototype.push.apply( section.screenshotQueue, newThemeControls ); // Add new themes to the screenshot queue.1958 1948 } 1949 1959 1950 _.delay( section.renderScreenshots, 100 ); // Wait for the controls to become visible. 1960 1951 1961 if ( ' installed' === section.params.action|| 100 > themes.length ) { // If we have less than the requested 100 themes, it's the end of the list.1952 if ( 'local' === section.params.filter_type || 100 > themes.length ) { // If we have less than the requested 100 themes, it's the end of the list. 1962 1953 section.fullyLoaded = true; 1963 1954 } … … 1970 1961 } 1971 1962 } 1972 if ( ' installed' === section.params.action) {1963 if ( 'local' === section.params.filter_type ) { 1973 1964 section.updateCount(); // Count of visible theme controls. 1974 1965 } else { … … 1996 1987 1997 1988 /** 1989 * Loads controls into the section from data received from loadThemes(). 1990 * 1991 * @since 4.9.0 1992 * @param {Array} themes - Array of theme data to create controls with. 1993 * @param {integer} page - Page of results being loaded. 1994 * @returns {void} 1995 */ 1996 loadControls: function( themes, page ) { 1997 var newThemeControls = [], 1998 section = this; 1999 2000 // Add controls for each theme. 2001 _.each( themes, function( theme ) { 2002 var themeControl = new api.controlConstructor.theme( section.params.action + '_theme_' + theme.id, { 2003 type: 'theme', 2004 section: section.params.id, 2005 theme: theme, 2006 priority: section.loaded + 1 2007 } ); 2008 2009 api.control.add( themeControl ); 2010 newThemeControls.push( themeControl ); 2011 section.loaded = section.loaded + 1; 2012 }); 2013 2014 if ( 1 !== page ) { 2015 Array.prototype.push.apply( section.screenshotQueue, newThemeControls ); // Add new themes to the screenshot queue. 2016 } 2017 }, 2018 2019 /** 1998 2020 * Determines whether more themes should be loaded, and loads them. 1999 2021 * … … 2010 2032 2011 2033 if ( bottom > threshold ) { 2012 section.load Controls();2034 section.loadThemes(); 2013 2035 } 2014 2036 } … … 2020 2042 * @since 4.9.0 2021 2043 * 2022 * @param { Element} el - The search input element as a raw JS object.2044 * @param {string} term - The raw search input value. 2023 2045 * @returns {void} 2024 2046 */ 2025 filterSearch: function( el) {2047 filterSearch: function( term ) { 2026 2048 var count = 0, 2027 2049 visible = false, 2028 2050 section = this, 2029 noFilter = ( undefined !== api.section( 'wporg_themes' ) && 'wporg' !== section.params.action) ? '.no-themes-local' : '.no-themes',2030 term = el.value.toLowerCase().trim().replace( '-', ' '),2031 controls = section.controls();2051 noFilter = ( api.section.has( 'wporg_themes' ) && 'remote' !== section.params.filter_type ) ? '.no-themes-local' : '.no-themes', 2052 controls = section.controls(), 2053 terms; 2032 2054 2033 2055 if ( section.loading ) { … … 2035 2057 } 2036 2058 2059 // Standardize search term format and split into an array of individual words. 2060 terms = term.toLowerCase().trim().replace( /-/g, ' ' ).split( ' ' ); 2061 2037 2062 _.each( controls, function( control ) { 2038 visible = control.filter( term );2063 visible = control.filter( terms ); // Shows/hides and sorts control based on the applicability of the search term. 2039 2064 if ( visible ) { 2040 2065 count = count + 1; … … 2050 2075 2051 2076 section.renderScreenshots(); 2077 api.reflowPaneContents(); 2052 2078 2053 2079 // Update theme count. … … 2065 2091 checkTerm: function( section ) { 2066 2092 var newTerm; 2067 if ( ' wporg' === section.params.action) {2093 if ( 'remote' === section.params.filter_type ) { 2068 2094 newTerm = section.contentContainer.find( '.wp-filter-search' ).val(); 2069 2095 if ( section.term !== newTerm ) { … … 2105 2131 section.nextTags = tags; 2106 2132 } else { 2107 section.initializeNewQuery( section.term, tags ); 2133 if ( 'remote' === section.params.filter_type ) { 2134 section.initializeNewQuery( section.term, tags ); 2135 } else if ( 'local' === section.params.filter_type ) { 2136 section.filterSearch( tags.join( ' ' ) ); 2137 } 2108 2138 } 2109 2139 } … … 2131 2161 section.screenshotQueue = null; 2132 2162 2133 // Run a new query, with load Controls handling paging, etc.2163 // Run a new query, with loadThemes handling paging, etc. 2134 2164 if ( ! section.loading ) { 2135 2165 section.term = newTerm; 2136 2166 section.tags = newTags; 2137 section.load Controls();2167 section.loadThemes(); 2138 2168 } else { 2139 section.nextTerm = newTerm; // This will reload from load Controls() with the newest term once the current batch is loaded.2140 section.nextTags = newTags; // This will reload from load Controls() with the newest tags once the current batch is loaded.2169 section.nextTerm = newTerm; // This will reload from loadThemes() with the newest term once the current batch is loaded. 2170 section.nextTags = newTags; // This will reload from loadThemes() with the newest tags once the current batch is loaded. 2141 2171 } 2142 2172 if ( ! section.expanded() ) { … … 4876 4906 * 4877 4907 * @since 4.2.0 4908 * @param {Array} terms - An array of terms to search for. 4878 4909 * @returns {boolean} Whether a theme control was activated or not. 4879 4910 */ 4880 filter: function( term ) {4911 filter: function( terms ) { 4881 4912 var control = this, 4913 matchCount = 0, 4882 4914 haystack = control.params.theme.name + ' ' + 4883 4915 control.params.theme.description + ' ' + 4884 4916 control.params.theme.tags + ' ' + 4885 control.params.theme.author ;4917 control.params.theme.author + ' '; 4886 4918 haystack = haystack.toLowerCase().replace( '-', ' ' ); 4887 if ( -1 !== haystack.search( term ) ) { 4919 4920 // Back-compat for behavior in WordPress 4.2.0 to 4.8.X. 4921 if ( ! _.isArray( terms ) ) { 4922 terms = [ terms ]; 4923 } 4924 4925 // Always give exact name matches highest ranking. 4926 if ( control.params.theme.name.toLowerCase() === terms.join( ' ' ) ) { 4927 matchCount = 100; 4928 } else { 4929 4930 // Search for and weight (by 10) complete term matches. 4931 matchCount = matchCount + 10 * ( haystack.split( terms.join( ' ' ) ).length - 1 ); 4932 4933 // Search for each term individually (as whole-word and partial match) and sum weighted match counts. 4934 _.each( terms, function( term ) { 4935 matchCount = matchCount + 2 * ( haystack.split( term + ' ' ).length - 1 ); // Whole-word, double-weighted. 4936 matchCount = matchCount + haystack.split( term ).length - 1; // Partial word, to minimize empty intermediate searches while typing. 4937 }); 4938 4939 // Upper limit on match ranking. 4940 if ( matchCount > 99 ) { 4941 matchCount = 99; 4942 } 4943 } 4944 4945 if ( 0 !== matchCount ) { 4888 4946 control.activate(); 4947 control.params.priority = 101 - matchCount; // Sort results by match count. 4889 4948 return true; 4890 4949 } else { 4891 control.deactivate(); 4950 control.deactivate(); // Hide control 4951 control.params.priority = 101; 4892 4952 return false; 4893 4953 } -
trunk/src/wp-includes/class-wp-customize-manager.php
r41802 r41807 4416 4416 'title' => __( 'WordPress.org themes' ), 4417 4417 'action' => 'wporg', 4418 'filter_type' => 'remote', 4418 4419 'capability' => 'install_themes', 4419 4420 'panel' => 'themes', … … 4948 4949 $theme_action = sanitize_key( $_POST['theme_action'] ); 4949 4950 $themes = array(); 4951 $args = array(); 4952 4953 // Define query filters based on user input. 4954 if ( ! array_key_exists( 'search', $_POST ) ) { 4955 $args['search'] = ''; 4956 } else { 4957 $args['search'] = sanitize_text_field( wp_unslash( $_POST['search'] ) ); 4958 } 4959 4960 if ( ! array_key_exists( 'tags', $_POST ) ) { 4961 $args['tag'] = ''; 4962 } else { 4963 $args['tag'] = array_map( 'sanitize_text_field', wp_unslash( (array) $_POST['tags'] ) ); 4964 } 4965 4966 if ( ! array_key_exists( 'page', $_POST ) ) { 4967 $args['page'] = 1; 4968 } else { 4969 $args['page'] = absint( $_POST['page'] ); 4970 } 4950 4971 4951 4972 require_once ABSPATH . 'wp-admin/includes/theme.php'; 4973 4952 4974 if ( 'installed' === $theme_action ) { 4975 4976 // Load all installed themes from wp_prepare_themes_for_js(). 4953 4977 $themes = array( 'themes' => wp_prepare_themes_for_js() ); 4954 4978 foreach ( $themes['themes'] as &$theme ) { … … 4956 4980 $theme['active'] = ( isset( $_POST['customized_theme'] ) && $_POST['customized_theme'] === $theme['id'] ); 4957 4981 } 4982 4958 4983 } elseif ( 'wporg' === $theme_action ) { 4984 4985 // Load WordPress.org themes from the .org API and normalize data to match installed theme objects. 4959 4986 if ( ! current_user_can( 'install_themes' ) ) { 4960 4987 wp_die( -1 ); … … 4962 4989 4963 4990 // Arguments for all queries. 4964 $ args = array(4991 $wporg_args = array( 4965 4992 'per_page' => 100, 4966 'page' => isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1,4967 4993 'fields' => array( 4968 4994 'screenshot_url' => true, … … 4980 5006 ); 4981 5007 4982 // Define query filters based on user input. 4983 if ( ! array_key_exists( 'search', $_POST ) ) { 4984 $args['search'] = ''; 4985 } else { 4986 $args['search'] = sanitize_text_field( wp_unslash( $_POST['search'] ) ); 4987 } 4988 4989 if ( ! array_key_exists( 'tags', $_POST ) ) { 4990 $args['tag'] = ''; 4991 } else { 4992 $args['tag'] = array_map( 'sanitize_text_field', wp_unslash( (array) $_POST['tags'] ) ); 4993 } 5008 $args = array_merge( $wporg_args, $args ); 4994 5009 4995 5010 if ( '' === $args['search'] && '' === $args['tag'] ) { … … 5062 5077 } // End foreach(). 5063 5078 } // End if(). 5079 5080 /** 5081 * Filters the theme data loaded in the customizer. 5082 * 5083 * This allows theme data to be loading from an external source, 5084 * or modification of data loaded from `wp_prepare_themes_for_js()` 5085 * or WordPress.org via `themes_api()`. 5086 * 5087 * @since 4.9.0 5088 * 5089 * @see wp_prepare_themes_for_js() 5090 * @see themes_api() 5091 * @see WP_Customize_Manager::__construct() 5092 * 5093 * @param array $themes Nested array of theme data. 5094 * @param array $args List of arguments, such as page, search term, and tags to query for. 5095 * @param WP_Customize_Manager $manager Instance of Customize manager. 5096 */ 5097 $themes = apply_filters( 'customize_load_themes', $themes, $args, $this ); 5098 5064 5099 wp_send_json_success( $themes ); 5065 5100 } -
trunk/src/wp-includes/customize/class-wp-customize-themes-section.php
r41709 r41807 38 38 39 39 /** 40 * Theme section filter type. 41 * 42 * Determines whether filters are applied to loaded (local) themes or by initiating a new remote query (remote). 43 * When filtering is local, the initial themes query is not paginated by default. 44 * 45 * @since 4.9.0 46 * @var string 47 */ 48 public $filter_type = 'local'; 49 50 /** 40 51 * Get section parameters for JS. 41 52 * … … 46 57 $exported = parent::json(); 47 58 $exported['action'] = $this->action; 59 $exported['filter_type'] = $this->filter_type; 48 60 49 61 return $exported;
Note: See TracChangeset
for help on using the changeset viewer.