Skip to content

Commit de292d2

Browse files
committed
Grouped backports for the 4.7 branch.
- REST API: Increase the specificity of capability checks for collections when the `edit` context is in use. - Menus: Prevent HTML in menu item titles from being rendered unexpectedly. Merges [60814], [60815], [60816] to the 4.7 branch. Props andraganescu, desrosj, ehti, hurayraiit, iandunn, joehoyle, johnbillion, jorbin, mnelson4, noisysocks, peterwilsoncc, phillsav, rmccue, timothyblynjacobs, vortfu, westonruter , whyisjake, zieladam. git-svn-id: https://develop.svn.wordpress.org/branches/4.7@60839 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 42f16ac commit de292d2

File tree

11 files changed

+206
-100
lines changed

11 files changed

+206
-100
lines changed

src/wp-admin/js/customize-nav-menus.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,13 @@
516516
return;
517517
}
518518

519-
this.currentMenuControl.addItemToMenu( menu_item.attributes );
519+
// Leave the title as empty to reuse the original title as a placeholder if set.
520+
var nav_menu_item = Object.assign( {}, menu_item.attributes );
521+
if ( nav_menu_item.title === nav_menu_item.original_title ) {
522+
nav_menu_item.title = '';
523+
}
524+
525+
this.currentMenuControl.addItemToMenu( nav_menu_item );
520526

521527
$( menuitemTpl ).find( '.menu-item-handle' ).addClass( 'item-added' );
522528
},
@@ -2633,7 +2639,6 @@
26332639
item,
26342640
{
26352641
nav_menu_term_id: menuControl.params.menu_id,
2636-
original_title: item.title,
26372642
position: position
26382643
}
26392644
);

src/wp-admin/js/nav-menu.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,20 +1157,27 @@ var wpNavMenu;
11571157
},
11581158

11591159
eventOnClickMenuSave : function() {
1160-
var locs = '',
1161-
menuName = $('#menu-name'),
1162-
menuNameVal = menuName.val();
1163-
// Cancel and warn if invalid menu name
1160+
var menuName = $('#menu-name'),
1161+
menuNameVal = menuName.val();
1162+
1163+
// Cancel and warn if invalid menu name.
11641164
if( !menuNameVal || menuNameVal == menuName.attr('title') || !menuNameVal.replace(/\s+/, '') ) {
11651165
menuName.parent().addClass('form-invalid');
11661166
return false;
11671167
}
1168-
// Copy menu theme locations
1168+
// Copy menu theme locations.
1169+
// Note: This appears to be dead code since #nav-menu-theme-locations no longer exists, perhaps removed in r32842.
1170+
var $updateNavMenu = $('#update-nav-menu');
11691171
$('#nav-menu-theme-locations select').each(function() {
1170-
locs += '<input type="hidden" name="' + this.name + '" value="' + $(this).val() + '" />';
1172+
$updateNavMenu.append(
1173+
$( '<input>', {
1174+
type: 'hidden',
1175+
name: this.name,
1176+
value: $( this ).val()
1177+
} )
1178+
);
11711179
});
1172-
$('#update-nav-menu').append( locs );
1173-
// Update menu item position data
1180+
// Update menu item position data.
11741181
api.menuList.find('.menu-item-data-position').val( function(index) { return index + 1; } );
11751182
window.onbeforeunload = null;
11761183

@@ -1210,7 +1217,10 @@ var wpNavMenu;
12101217
$item;
12111218

12121219
if( ! $items.length ) {
1213-
$('.categorychecklist', panel).html( '<li><p>' + navMenuL10n.noResultsFound + '</p></li>' );
1220+
var li = $( '<li>' );
1221+
var p = $( '<p>', { text: navMenuL10n.noResultsFound } );
1222+
li.append( p );
1223+
$('.categorychecklist', panel).empty().append( li );
12141224
$( '.spinner', panel ).removeClass( 'is-active' );
12151225
wrapper.addClass( 'has-no-menu-item' );
12161226
return;

src/wp-includes/class-wp-customize-nav-menus.php

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,15 @@ public function load_available_items_query( $type = 'post_type', $object = 'page
164164
);
165165
} elseif ( 'post' !== $object && 0 === $page && $post_type->has_archive ) {
166166
// Add a post type archive link.
167+
$title = $post_type->labels->archives;
167168
$items[] = array(
168-
'id' => $object . '-archive',
169-
'title' => $post_type->labels->archives,
170-
'type' => 'post_type_archive',
171-
'type_label' => __( 'Post Type Archive' ),
172-
'object' => $object,
173-
'url' => get_post_type_archive_link( $object ),
169+
'id' => $object_name . '-archive',
170+
'title' => $title,
171+
'original_title' => $title,
172+
'type' => 'post_type_archive',
173+
'type_label' => __( 'Post Type Archive' ),
174+
'object' => $object_name,
175+
'url' => get_post_type_archive_link( $object_name ),
174176
);
175177
}
176178

@@ -199,14 +201,17 @@ public function load_available_items_query( $type = 'post_type', $object = 'page
199201
/* translators: %d: ID of a post */
200202
$post_title = sprintf( __( '#%d (no title)' ), $post->ID );
201203
}
204+
205+
$title = html_entity_decode( $post_title, ENT_QUOTES, get_bloginfo( 'charset' ) );
202206
$items[] = array(
203-
'id' => "post-{$post->ID}",
204-
'title' => html_entity_decode( $post_title, ENT_QUOTES, get_bloginfo( 'charset' ) ),
205-
'type' => 'post_type',
206-
'type_label' => get_post_type_object( $post->post_type )->labels->singular_name,
207-
'object' => $post->post_type,
208-
'object_id' => intval( $post->ID ),
209-
'url' => get_permalink( intval( $post->ID ) ),
207+
'id' => "post-{$post->ID}",
208+
'title' => $title,
209+
'original_title' => $title,
210+
'type' => 'post_type',
211+
'type_label' => get_post_type_object( $post->post_type )->labels->singular_name,
212+
'object' => $post->post_type,
213+
'object_id' => (int) $post->ID,
214+
'url' => get_permalink( (int) $post->ID ),
210215
);
211216
}
212217
} elseif ( 'taxonomy' === $type ) {
@@ -227,14 +232,16 @@ public function load_available_items_query( $type = 'post_type', $object = 'page
227232
}
228233

229234
foreach ( $terms as $term ) {
235+
$title = html_entity_decode( $term->name, ENT_QUOTES, get_bloginfo( 'charset' ) );
230236
$items[] = array(
231-
'id' => "term-{$term->term_id}",
232-
'title' => html_entity_decode( $term->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
233-
'type' => 'taxonomy',
234-
'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name,
235-
'object' => $term->taxonomy,
236-
'object_id' => intval( $term->term_id ),
237-
'url' => get_term_link( intval( $term->term_id ), $term->taxonomy ),
237+
'id' => "term-{$term->term_id}",
238+
'title' => $title,
239+
'original_title' => $title,
240+
'type' => 'taxonomy',
241+
'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name,
242+
'object' => $term->taxonomy,
243+
'object_id' => (int) $term->term_id,
244+
'url' => get_term_link( (int) $term->term_id, $term->taxonomy ),
238245
);
239246
}
240247
}

src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting {
5858
'classes' => '',
5959
'xfn' => '',
6060
'status' => 'publish',
61-
'original_title' => '',
6261
'nav_menu_term_id' => 0, // This will be supplied as the $menu_id arg for wp_update_nav_menu_item().
6362
'_invalid' => false,
6463
);
@@ -224,7 +223,8 @@ public function flush_cached_value( $menu_id, $menu_item_id ) {
224223
* @return array|false Instance data array, or false if the item is marked for deletion.
225224
*/
226225
public function value() {
227-
if ( $this->is_previewed && $this->_previewed_blog_id === get_current_blog_id() ) {
226+
$type_label = null;
227+
if ( $this->is_previewed && get_current_blog_id() === $this->_previewed_blog_id ) {
228228
$undefined = new stdClass(); // Symbol.
229229
$post_value = $this->post_value( $undefined );
230230

@@ -233,9 +233,6 @@ public function value() {
233233
} else {
234234
$value = $post_value;
235235
}
236-
if ( ! empty( $value ) && empty( $value['original_title'] ) ) {
237-
$value['original_title'] = $this->get_original_title( (object) $value );
238-
}
239236
} elseif ( isset( $this->value ) ) {
240237
$value = $this->value;
241238
} else {
@@ -247,6 +244,9 @@ public function value() {
247244
if ( $post && self::POST_TYPE === $post->post_type ) {
248245
$is_title_empty = empty( $post->post_title );
249246
$value = (array) wp_setup_nav_menu_item( $post );
247+
if ( isset( $value['type_label'] ) ) {
248+
$type_label = $value['type_label'];
249+
}
250250
if ( $is_title_empty ) {
251251
$value['title'] = '';
252252
}
@@ -263,21 +263,40 @@ public function value() {
263263
$value = $this->value;
264264
}
265265

266-
if ( ! empty( $value ) && empty( $value['type_label'] ) ) {
267-
$value['type_label'] = $this->get_type_label( (object) $value );
266+
// These properties are read-only and are part of the setting for use in the Customizer UI.
267+
if ( is_array( $value ) ) {
268+
$value_obj = (object) $value;
269+
$value['type_label'] = isset( $type_label ) ? $type_label : $this->get_type_label( $value_obj );
270+
$value['original_title'] = $this->get_original_title( $value_obj );
268271
}
269272

270273
return $value;
271274
}
272275

276+
/**
277+
* Prepares the value for editing on the client.
278+
*
279+
* @since 6.8.3
280+
*
281+
* @return array|false Value prepared for the client.
282+
*/
283+
public function js_value() {
284+
$value = parent::js_value();
285+
if ( is_array( $value ) && isset( $value['original_title'] ) ) {
286+
// Decode entities for the sake of displaying the original title as a placeholder.
287+
$value['original_title'] = html_entity_decode( $value['original_title'], ENT_QUOTES, get_bloginfo( 'charset' ) );
288+
}
289+
return $value;
290+
}
291+
273292
/**
274293
* Get original title.
275294
*
276295
* @since 4.7.0
277296
* @access protected
278297
*
279298
* @param object $item Nav menu item.
280-
* @return string The original title.
299+
* @return string The original title, without entity decoding.
281300
*/
282301
protected function get_original_title( $item ) {
283302
$original_title = '';
@@ -303,7 +322,6 @@ protected function get_original_title( $item ) {
303322
$original_title = $original_object->labels->archives;
304323
}
305324
}
306-
$original_title = html_entity_decode( $original_title, ENT_QUOTES, get_bloginfo( 'charset' ) );
307325
return $original_title;
308326
}
309327

@@ -363,10 +381,6 @@ protected function populate_value() {
363381
unset( $this->value['post_status'] );
364382
}
365383

366-
if ( ! isset( $this->value['original_title'] ) ) {
367-
$this->value['original_title'] = $this->get_original_title( (object) $this->value );
368-
}
369-
370384
if ( ! isset( $this->value['nav_menu_term_id'] ) && $this->post_id > 0 ) {
371385
$menus = wp_get_post_terms( $this->post_id, WP_Customize_Nav_Menu_Setting::TAXONOMY, array(
372386
'fields' => 'ids',
@@ -606,11 +620,8 @@ public function value_as_wp_post_nav_menu_item() {
606620
$item->menu_order = $item->position;
607621
unset( $item->position );
608622

609-
if ( empty( $item->original_title ) ) {
610-
$item->original_title = $this->get_original_title( $item );
611-
}
612623
if ( empty( $item->title ) && ! empty( $item->original_title ) ) {
613-
$item->title = $item->original_title;
624+
$item->title = $item->original_title; // This is NOT entity-decoded. It comes from self::get_original_title().
614625
}
615626
if ( $item->title ) {
616627
$item->post_title = $item->title;
@@ -661,7 +672,7 @@ public function value_as_wp_post_nav_menu_item() {
661672
* @since 4.3.0
662673
* @access public
663674
*
664-
* @param array $menu_item_value The value to sanitize.
675+
* @param array|false $menu_item_value The value to sanitize.
665676
* @return array|false|null Null if an input isn't valid. False if it is marked for deletion.
666677
* Otherwise the sanitized value.
667678
*/
@@ -715,8 +726,6 @@ public function sanitize( $menu_item_value ) {
715726
$menu_item_value[ $key ] = implode( ' ', array_map( 'sanitize_html_class', $value ) );
716727
}
717728

718-
$menu_item_value['original_title'] = sanitize_text_field( $menu_item_value['original_title'] );
719-
720729
// Apply the same filters as when calling wp_insert_post().
721730
$menu_item_value['title'] = wp_unslash( apply_filters( 'title_save_pre', wp_slash( $menu_item_value['title'] ) ) );
722731
$menu_item_value['attr_title'] = wp_unslash( apply_filters( 'excerpt_save_pre', wp_slash( $menu_item_value['attr_title'] ) ) );

src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,13 @@ public function get_items( $request ) {
344344
$posts = array();
345345

346346
foreach ( $query_result as $post ) {
347-
if ( ! $this->check_read_permission( $post ) ) {
347+
if ( 'edit' === $request['context'] ) {
348+
$permission = $this->check_update_permission( $post );
349+
} else {
350+
$permission = $this->check_read_permission( $post );
351+
}
352+
353+
if ( ! $permission ) {
348354
continue;
349355
}
350356

src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ public function get_items( $request ) {
316316
$response = array();
317317

318318
foreach ( $query_result as $term ) {
319+
if ( 'edit' === $request['context'] && ! current_user_can( 'edit_term', $term->term_id ) ) {
320+
continue;
321+
}
319322
$data = $this->prepare_item_for_response( $term, $request );
320323
$response[] = $this->prepare_response_for_collection( $data );
321324
}

src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public function get_items_permissions_check( $request ) {
183183
}
184184

185185
if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) {
186-
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to list users.' ), array( 'status' => rest_authorization_required_code() ) );
186+
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit users.' ), array( 'status' => rest_authorization_required_code() ) );
187187
}
188188

189189
if ( in_array( $request['orderby'], array( 'email', 'registered_date' ), true ) && ! current_user_can( 'list_users' ) ) {
@@ -281,6 +281,9 @@ public function get_items( $request ) {
281281
$users = array();
282282

283283
foreach ( $query->results as $user ) {
284+
if ( 'edit' === $request['context'] && ! current_user_can( 'edit_user', $user->ID ) ) {
285+
continue;
286+
}
284287
$data = $this->prepare_item_for_response( $user, $request );
285288
$users[] = $this->prepare_response_for_collection( $data );
286289
}
@@ -376,9 +379,11 @@ public function get_item_permissions_check( $request ) {
376379
return true;
377380
}
378381

379-
if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) {
380-
return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to list users.' ), array( 'status' => rest_authorization_required_code() ) );
381-
} elseif ( ! count_user_posts( $user->ID, $types ) && ! current_user_can( 'edit_user', $user->ID ) && ! current_user_can( 'list_users' ) ) {
382+
if ( 'edit' === $request['context'] && ! current_user_can( 'edit_user', $user->ID ) ) {
383+
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this user.' ), array( 'status' => rest_authorization_required_code() ) );
384+
}
385+
386+
if ( ! current_user_can( 'edit_user', $user->ID ) && ! current_user_can( 'list_users' ) && ! count_user_posts( $user->ID, $types ) ) {
382387
return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to list users.' ), array( 'status' => rest_authorization_required_code() ) );
383388
}
384389

@@ -878,7 +883,7 @@ public function prepare_item_for_response( $user, $request ) {
878883
$data['slug'] = $user->user_nicename;
879884
}
880885

881-
if ( ! empty( $schema['properties']['roles'] ) ) {
886+
if ( ! empty( $schema['properties']['roles'] ) && ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) ) {
882887
// Defensively call array_values() to ensure an array is returned.
883888
$data['roles'] = array_values( $user->roles );
884889
}

0 commit comments

Comments
 (0)