diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js
index 0ea60ce..851eaf3 100644
|
|
|
1 | 1 | /* globals _wpCustomizeHeader, _wpMediaViewsL10n */ |
2 | 2 | (function( exports, $ ){ |
3 | | var bubbleChildValueChanges, Container, focus, isKeydownButNotEnterEvent, areElementListsEqual, api = wp.customize; |
| 3 | var bubbleChildValueChanges, Container, focus, isKeydownButNotEnterEvent, areElementListsEqual, stableSort, api = wp.customize; |
4 | 4 | |
5 | 5 | // @todo Move private helper functions to wp.customize.utils so they can be unit tested |
6 | 6 | |
… |
… |
|
78 | 78 | }; |
79 | 79 | |
80 | 80 | /** |
| 81 | * Stable sort for Panels, Sections, and Controls. |
| 82 | * |
| 83 | * If a.priority() === b.priority(), then sort by their respective params.instanceNumber. |
| 84 | * |
| 85 | * @param {(wp.customize.Panel|wp.customize.Section|wp.customize.Control)} a |
| 86 | * @param {(wp.customize.Panel|wp.customize.Section|wp.customize.Control)} b |
| 87 | * @returns {Number} |
| 88 | */ |
| 89 | stableSort = function ( a, b ) { |
| 90 | if ( a.priority() === b.priority() && typeof a.params.instanceNumber === 'number' && typeof b.params.instanceNumber === 'number' ) { |
| 91 | return a.params.instanceNumber - b.params.instanceNumber; |
| 92 | } else { |
| 93 | return a.priority() - b.priority(); |
| 94 | } |
| 95 | }; |
| 96 | |
| 97 | /** |
81 | 98 | * Return whether the supplied Event object is for a keydown event but not the Enter key. |
82 | 99 | * |
83 | 100 | * @param {jQuery.Event} event |
… |
… |
|
176 | 193 | children.push( child ); |
177 | 194 | } |
178 | 195 | } ); |
179 | | children.sort( function ( a, b ) { |
180 | | return a.priority() - b.priority(); |
181 | | } ); |
| 196 | children.sort( stableSort ); |
182 | 197 | return children; |
183 | 198 | }, |
184 | 199 | |
… |
… |
|
1952 | 1967 | } ); |
1953 | 1968 | |
1954 | 1969 | // Sort the root panels and sections |
1955 | | rootNodes.sort( function ( a, b ) { |
1956 | | return a.priority() - b.priority(); |
1957 | | } ); |
| 1970 | rootNodes.sort( stableSort ); |
1958 | 1971 | rootContainers = _.pluck( rootNodes, 'container' ); |
1959 | 1972 | appendContainer = $( '#customize-theme-controls' ).children( 'ul' ); // @todo This should be defined elsewhere, and to be configurable |
1960 | 1973 | if ( ! areElementListsEqual( rootContainers, appendContainer.children() ) ) { |
diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php
index dcebb0f..a2df83f 100644
|
|
|
7 | 7 | * @since 3.4.0 |
8 | 8 | */ |
9 | 9 | class WP_Customize_Control { |
| 10 | |
| 11 | /** |
| 12 | * Incremented with each new class instantiation, then stored in $instance_number. |
| 13 | * |
| 14 | * Used when sorting two instances whose priorities are equal. |
| 15 | * |
| 16 | * @since 4.1.0 |
| 17 | * @access protected |
| 18 | * @var int |
| 19 | */ |
| 20 | protected static $instance_count = 0; |
| 21 | |
| 22 | /** |
| 23 | * Order in which this instance was created in relation to other instances. |
| 24 | * |
| 25 | * @since 4.1.0 |
| 26 | * @access public |
| 27 | * @var int |
| 28 | */ |
| 29 | public $instance_number; |
| 30 | |
10 | 31 | /** |
11 | 32 | * @access public |
12 | 33 | * @var WP_Customize_Manager |
… |
… |
class WP_Customize_Control { |
127 | 148 | if ( empty( $this->active_callback ) ) { |
128 | 149 | $this->active_callback = array( $this, 'active_callback' ); |
129 | 150 | } |
| 151 | self::$instance_count += 1; |
| 152 | $this->instance_number = self::$instance_count; |
130 | 153 | |
131 | 154 | // Process settings. |
132 | 155 | if ( empty( $this->settings ) ) { |
… |
… |
class WP_Customize_Control { |
218 | 241 | $this->json['settings'][ $key ] = $setting->id; |
219 | 242 | } |
220 | 243 | |
221 | | $this->json['type'] = $this->type; |
222 | | $this->json['priority'] = $this->priority; |
223 | | $this->json['active'] = $this->active(); |
224 | | $this->json['section'] = $this->section; |
225 | | $this->json['content'] = $this->get_content(); |
226 | | $this->json['label'] = $this->label; |
| 244 | $this->json['type'] = $this->type; |
| 245 | $this->json['priority'] = $this->priority; |
| 246 | $this->json['active'] = $this->active(); |
| 247 | $this->json['section'] = $this->section; |
| 248 | $this->json['content'] = $this->get_content(); |
| 249 | $this->json['label'] = $this->label; |
227 | 250 | $this->json['description'] = $this->description; |
| 251 | $this->json['instanceNumber'] = $this->instance_number; // note: camelCase for JS |
228 | 252 | } |
229 | 253 | |
230 | 254 | /** |
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php
index 371ea90..987edc6 100644
|
|
final class WP_Customize_Manager { |
856 | 856 | * @since 4.1.0 |
857 | 857 | */ |
858 | 858 | public function render_control_templates() { |
859 | | foreach( $this->registered_control_types as $control_type ) { |
| 859 | foreach ( $this->registered_control_types as $control_type ) { |
860 | 860 | $control = new $control_type( $this, 'temp', array() ); |
861 | 861 | $control->print_template(); |
862 | 862 | } |
863 | 863 | } |
864 | 864 | |
865 | | /** |
866 | | * Helper function to compare two objects by priority. |
| 865 | /** |
| 866 | * Helper function to compare two objects by priority, ensuring sort stability via instance_number. |
867 | 867 | * |
868 | 868 | * @since 3.4.0 |
869 | 869 | * |
870 | | * @param object $a Object A. |
871 | | * @param object $b Object B. |
| 870 | * @param {WP_Customize_Panel|WP_Customize_Section|WP_Customize_Control} $a Object A. |
| 871 | * @param {WP_Customize_Panel|WP_Customize_Section|WP_Customize_Control} $b Object B. |
872 | 872 | * @return int |
873 | 873 | */ |
874 | 874 | protected final function _cmp_priority( $a, $b ) { |
875 | | $ap = $a->priority; |
876 | | $bp = $b->priority; |
877 | | |
878 | | if ( $ap == $bp ) |
879 | | return 0; |
880 | | return ( $ap > $bp ) ? 1 : -1; |
| 875 | if ( $a->priority === $b->priority ) { |
| 876 | return $a->instance_number - $a->instance_number; |
| 877 | } else { |
| 878 | return $a->priority - $b->priority; |
| 879 | } |
881 | 880 | } |
882 | 881 | |
883 | 882 | /** |
… |
… |
final class WP_Customize_Manager { |
891 | 890 | */ |
892 | 891 | public function prepare_controls() { |
893 | 892 | |
894 | | $this->controls = array_reverse( $this->controls ); |
895 | 893 | $controls = array(); |
| 894 | uasort( $this->controls, array( $this, '_cmp_priority' ) ); |
896 | 895 | |
897 | 896 | foreach ( $this->controls as $id => $control ) { |
898 | 897 | if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() ) { |
… |
… |
final class WP_Customize_Manager { |
905 | 904 | $this->controls = $controls; |
906 | 905 | |
907 | 906 | // Prepare sections. |
908 | | // Reversing makes uasort sort by time added when conflicts occur. |
909 | | $this->sections = array_reverse( $this->sections ); |
910 | 907 | uasort( $this->sections, array( $this, '_cmp_priority' ) ); |
911 | 908 | $sections = array(); |
912 | 909 | |
… |
… |
final class WP_Customize_Manager { |
930 | 927 | $this->sections = $sections; |
931 | 928 | |
932 | 929 | // Prepare panels. |
933 | | // Reversing makes uasort sort by time added when conflicts occur. |
934 | | $this->panels = array_reverse( $this->panels ); |
935 | 930 | uasort( $this->panels, array( $this, '_cmp_priority' ) ); |
936 | 931 | $panels = array(); |
937 | 932 | |
diff --git src/wp-includes/class-wp-customize-panel.php src/wp-includes/class-wp-customize-panel.php
index 201c4b9..af8f243 100644
|
|
|
11 | 11 | class WP_Customize_Panel { |
12 | 12 | |
13 | 13 | /** |
| 14 | * Incremented with each new class instantiation, then stored in $instance_number. |
| 15 | * |
| 16 | * Used when sorting two instances whose priorities are equal. |
| 17 | * |
| 18 | * @since 4.1.0 |
| 19 | * @access protected |
| 20 | * @var int |
| 21 | */ |
| 22 | protected static $instance_count = 0; |
| 23 | |
| 24 | /** |
| 25 | * Order in which this instance was created in relation to other instances. |
| 26 | * |
| 27 | * @since 4.1.0 |
| 28 | * @access public |
| 29 | * @var int |
| 30 | */ |
| 31 | public $instance_number; |
| 32 | |
| 33 | /** |
14 | 34 | * WP_Customize_Manager instance. |
15 | 35 | * |
16 | 36 | * @since 4.0.0 |
… |
… |
class WP_Customize_Panel { |
128 | 148 | if ( empty( $this->active_callback ) ) { |
129 | 149 | $this->active_callback = array( $this, 'active_callback' ); |
130 | 150 | } |
| 151 | self::$instance_count += 1; |
| 152 | $this->instance_number = self::$instance_count; |
131 | 153 | |
132 | 154 | $this->sections = array(); // Users cannot customize the $sections array. |
133 | 155 | |
… |
… |
class WP_Customize_Panel { |
185 | 207 | $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'type' ) ); |
186 | 208 | $array['content'] = $this->get_content(); |
187 | 209 | $array['active'] = $this->active(); |
| 210 | $array['instanceNumber'] = $this->instance_number; // camelCase |
188 | 211 | return $array; |
189 | 212 | } |
190 | 213 | |
diff --git src/wp-includes/class-wp-customize-section.php src/wp-includes/class-wp-customize-section.php
index 3553285..a90feb5 100644
|
|
|
11 | 11 | class WP_Customize_Section { |
12 | 12 | |
13 | 13 | /** |
| 14 | * Incremented with each new class instantiation, then stored in $instance_number. |
| 15 | * |
| 16 | * Used when sorting two instances whose priorities are equal. |
| 17 | * |
| 18 | * @since 4.1.0 |
| 19 | * @access protected |
| 20 | * @var int |
| 21 | */ |
| 22 | protected static $instance_count = 0; |
| 23 | |
| 24 | /** |
| 25 | * Order in which this instance was created in relation to other instances. |
| 26 | * |
| 27 | * @since 4.1.0 |
| 28 | * @access public |
| 29 | * @var int |
| 30 | */ |
| 31 | public $instance_number; |
| 32 | |
| 33 | /** |
14 | 34 | * WP_Customize_Manager instance. |
15 | 35 | * |
16 | 36 | * @since 3.4.0 |
… |
… |
class WP_Customize_Section { |
137 | 157 | if ( empty( $this->active_callback ) ) { |
138 | 158 | $this->active_callback = array( $this, 'active_callback' ); |
139 | 159 | } |
| 160 | self::$instance_count += 1; |
| 161 | $this->instance_number = self::$instance_count; |
140 | 162 | |
141 | 163 | $this->controls = array(); // Users cannot customize the $controls array. |
142 | 164 | |
… |
… |
class WP_Customize_Section { |
194 | 216 | $array = wp_array_slice_assoc( (array) $this, array( 'title', 'description', 'priority', 'panel', 'type' ) ); |
195 | 217 | $array['content'] = $this->get_content(); |
196 | 218 | $array['active'] = $this->active(); |
| 219 | $array['instanceNumber'] = $this->instance_number; // camelCase |
197 | 220 | return $array; |
198 | 221 | } |
199 | 222 | |