Skip to content

Commit ef907f5

Browse files
Merge branch 'trunk' into fix/64986-preview-gettext-context
2 parents da1c382 + 609f25f commit ef907f5

25 files changed

Lines changed: 864 additions & 404 deletions

Gruntfile.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,7 @@ module.exports = function(grunt) {
18371837
'clean:js',
18381838
'build:webpack',
18391839
'copy:js',
1840+
'copy-vendor-scripts',
18401841
'file_append',
18411842
'uglify:all',
18421843
'concat:tinymce',
@@ -2133,7 +2134,6 @@ module.exports = function(grunt) {
21332134
'build:css',
21342135
'build:codemirror',
21352136
'build:gutenberg',
2136-
'copy-vendor-scripts',
21372137
'build:certificates'
21382138
] );
21392139
} else {
@@ -2145,7 +2145,6 @@ module.exports = function(grunt) {
21452145
'build:css',
21462146
'build:codemirror',
21472147
'build:gutenberg',
2148-
'copy-vendor-scripts',
21492148
'replace:source-maps',
21502149
'verify:build'
21512150
] );

src/wp-admin/css/color-picker.css

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
/* Needs higher specificity to override `.wp-core-ui .button`. */
1212
.wp-picker-container .wp-color-result.button {
13-
min-height: 30px;
13+
min-height: 32px;
1414
margin: 0 6px 6px 0;
1515
padding: 0 0 0 30px;
1616
font-size: 11px;
@@ -22,7 +22,7 @@
2222
border-left: 1px solid #c3c4c7;
2323
color: #50575e;
2424
display: block;
25-
line-height: 2.54545455; /* 28px */
25+
line-height: 2.72727273; /* 30px */
2626
padding: 0 6px;
2727
text-align: center;
2828
}
@@ -76,8 +76,8 @@
7676
.wp-customizer .wp-picker-input-wrap .button.wp-picker-clear {
7777
margin-left: 6px;
7878
padding: 0 8px;
79-
line-height: 2.54545455; /* 28px */
80-
min-height: 30px;
79+
line-height: 2.72727273; /* 30px */
80+
min-height: 32px;
8181
}
8282

8383
.wp-picker-container .iris-square-slider .ui-slider-handle:focus {
@@ -97,7 +97,7 @@
9797
margin: 0;
9898
padding: 0 5px;
9999
vertical-align: top;
100-
min-height: 30px;
100+
min-height: 32px;
101101
}
102102

103103
.wp-color-picker::-webkit-input-placeholder {

src/wp-admin/css/common.css

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,22 +1473,22 @@ div.error p,
14731473
color: #1e1e1e;
14741474
}
14751475

1476-
.notice a,
1477-
.error a,
1478-
.updated a {
1476+
div.notice a,
1477+
div.error a,
1478+
div.updated a {
14791479
color: var(--wp-admin-theme-color-darker-10);
14801480
text-decoration: underline;
14811481
}
14821482

1483-
.notice a:hover,
1484-
.error a:hover,
1485-
.updated a:hover {
1483+
div.notice a:hover,
1484+
div.error a:hover,
1485+
div.updated a:hover {
14861486
color: var(--wp-admin-theme-color-darker-20);
14871487
}
14881488

1489-
.notice a:focus,
1490-
.error a:focus,
1491-
.updated a:focus {
1489+
div.notice a:focus,
1490+
div.error a:focus,
1491+
div.updated a:focus {
14921492
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
14931493
outline: 2px solid transparent;
14941494
border-radius: 2px;
@@ -2077,17 +2077,6 @@ p.auto-update-status {
20772077
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02), 0 1px 0 rgba(0, 0, 0, 0.02);
20782078
}
20792079

2080-
.contextual-help-tabs .active::after {
2081-
content: "";
2082-
position: absolute;
2083-
top: 0;
2084-
right: -1px;
2085-
width: 2px;
2086-
height: 100%;
2087-
background: inherit;
2088-
z-index: 2;
2089-
}
2090-
20912080
.contextual-help-tabs .active a {
20922081
border-color: #c3c4c7;
20932082
color: #2c3338;
@@ -2292,7 +2281,7 @@ html.wp-toolbar {
22922281
line-height: 1;
22932282
}
22942283

2295-
.postbox.closed {
2284+
.postbox.closed .postbox-header {
22962285
border-bottom: 0;
22972286
}
22982287

src/wp-admin/css/edit.css

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -994,15 +994,16 @@ form#tags-filter {
994994
}
995995

996996
.privacy-settings-accordion-actions {
997-
text-align: right;
998-
display: block;
997+
justify-content: right;
998+
display: flex;
999+
align-items: center;
1000+
flex-wrap: wrap;
1001+
gap: 1em;
9991002
}
10001003

10011004
.privacy-settings-accordion-actions .success {
10021005
display: none;
10031006
color: #007017;
1004-
padding-right: 1em;
1005-
padding-top: 6px;
10061007
}
10071008

10081009
.privacy-settings-accordion-actions .success.visible {

src/wp-admin/includes/class-wp-posts-list-table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ protected function get_bulk_actions() {
437437
if ( $this->is_trash ) {
438438
$actions['untrash'] = __( 'Restore' );
439439
} else {
440-
$actions['edit'] = __( 'Bulk edit' );
440+
$actions['edit'] = _x( 'Bulk edit', 'verb' );
441441
}
442442
}
443443

src/wp-admin/includes/meta-boxes.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1453,7 +1453,14 @@ function link_advanced_meta_box( $link ) {
14531453
<td><input name="link_rss" class="code" type="text" id="rss_uri" maxlength="255" value="<?php echo ( isset( $link->link_rss ) ? esc_attr( $link->link_rss ) : '' ); ?>" /></td>
14541454
</tr>
14551455
<tr>
1456-
<th scope="row"><label for="link_notes"><?php _e( 'Notes' ); ?></label></th>
1456+
<th scope="row">
1457+
<label for="link_notes">
1458+
<?php
1459+
/* translators: Label for the Notes textarea in the Link Manager edit screen. */
1460+
_ex( 'Notes', 'Link manager notes field label' );
1461+
?>
1462+
</label>
1463+
</th>
14571464
<td><textarea name="link_notes" id="link_notes" rows="10"><?php echo $link->link_notes ?? ''; // textarea_escaped ?></textarea></td>
14581465
</tr>
14591466
<tr>

src/wp-includes/class-wp-block-patterns-registry.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,9 @@ public function get_registered( $pattern_name ) {
227227
* and per style.
228228
*/
229229
public function get_all_registered( $outside_init_only = false ) {
230-
$patterns = $outside_init_only
231-
? $this->registered_patterns_outside_init
232-
: $this->registered_patterns;
233-
$hooked_blocks = get_hooked_blocks();
230+
$patterns = $outside_init_only
231+
? $this->registered_patterns_outside_init
232+
: $this->registered_patterns;
234233

235234
foreach ( $patterns as $index => $pattern ) {
236235
$content = $this->get_content( $pattern['name'], $outside_init_only );

src/wp-includes/class-wp-connector-registry.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
* env_var_name?: non-empty-string
4141
* },
4242
* plugin?: array{
43-
* slug: non-empty-string
43+
* file: non-empty-string
4444
* }
4545
* }
4646
*/
@@ -109,7 +109,8 @@ final class WP_Connector_Registry {
109109
* @type array $plugin {
110110
* Optional. Plugin data for install/activate UI.
111111
*
112-
* @type string $slug The WordPress.org plugin slug.
112+
* @type string $file The plugin's main file path relative to the plugins
113+
* directory (e.g. 'akismet/akismet.php' or 'hello.php').
113114
* }
114115
* }
115116
* @return array|null The registered connector data on success, null on failure.
@@ -242,8 +243,8 @@ public function register( string $id, array $args ): ?array {
242243
}
243244
}
244245

245-
if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) ) {
246-
$connector['plugin'] = $args['plugin'];
246+
if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) && ! empty( $args['plugin']['file'] ) ) {
247+
$connector['plugin'] = array( 'file' => $args['plugin']['file'] );
247248
}
248249

249250
$this->registered_connectors[ $id ] = $connector;

src/wp-includes/collaboration/class-wp-http-polling-sync-server.php

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,30 @@ class WP_HTTP_Polling_Sync_Server {
3737
*/
3838
const COMPACTION_THRESHOLD = 50;
3939

40+
/**
41+
* Maximum total size (in bytes) of the request body.
42+
*
43+
* @since 7.0.0
44+
* @var int
45+
*/
46+
const MAX_BODY_SIZE = 16 * MB_IN_BYTES;
47+
48+
/**
49+
* Maximum number of rooms allowed per request.
50+
*
51+
* @since 7.0.0
52+
* @var int
53+
*/
54+
const MAX_ROOMS_PER_REQUEST = 50;
55+
56+
/**
57+
* Maximum length of a single update data string.
58+
*
59+
* @since 7.0.0
60+
* @var int
61+
*/
62+
const MAX_UPDATE_DATA_SIZE = MB_IN_BYTES;
63+
4064
/**
4165
* Sync update type: compaction.
4266
*
@@ -96,8 +120,9 @@ public function register_routes(): void {
96120
$typed_update_args = array(
97121
'properties' => array(
98122
'data' => array(
99-
'type' => 'string',
100-
'required' => true,
123+
'type' => 'string',
124+
'required' => true,
125+
'maxLength' => self::MAX_UPDATE_DATA_SIZE,
101126
),
102127
'type' => array(
103128
'type' => 'string',
@@ -149,12 +174,14 @@ public function register_routes(): void {
149174
'methods' => array( WP_REST_Server::CREATABLE ),
150175
'callback' => array( $this, 'handle_request' ),
151176
'permission_callback' => array( $this, 'check_permissions' ),
177+
'validate_callback' => array( $this, 'validate_request' ),
152178
'args' => array(
153179
'rooms' => array(
154180
'items' => array(
155181
'properties' => $room_args,
156182
'type' => 'object',
157183
),
184+
'maxItems' => self::MAX_ROOMS_PER_REQUEST,
158185
'required' => true,
159186
'type' => 'array',
160187
),
@@ -223,6 +250,30 @@ public function check_permissions( WP_REST_Request $request ) {
223250
return true;
224251
}
225252

253+
/**
254+
* Validates that the request body does not exceed the maximum allowed size.
255+
*
256+
* Runs as the route-level validate_callback, after per-arg schema
257+
* validation has already passed.
258+
*
259+
* @since 7.0.0
260+
*
261+
* @param WP_REST_Request $request The REST request.
262+
* @return true|WP_Error True if valid, WP_Error if the body is too large.
263+
*/
264+
public function validate_request( WP_REST_Request $request ) {
265+
$body = $request->get_body();
266+
if ( is_string( $body ) && strlen( $body ) > self::MAX_BODY_SIZE ) {
267+
return new WP_Error(
268+
'rest_sync_body_too_large',
269+
__( 'Request body is too large.' ),
270+
array( 'status' => 413 )
271+
);
272+
}
273+
274+
return true;
275+
}
276+
226277
/**
227278
* Handles request: stores sync updates and awareness data, and returns
228279
* updates the client is missing.
@@ -278,24 +329,47 @@ public function handle_request( WP_REST_Request $request ) {
278329
*
279330
* @param string $entity_kind The entity kind, e.g. 'postType', 'taxonomy', 'root'.
280331
* @param string $entity_name The entity name, e.g. 'post', 'category', 'site'.
281-
* @param string|null $object_id The object ID / entity key for single entities, null for collections.
332+
* @param string|null $object_id The numeric object ID / entity key for single entities, null for collections.
282333
* @return bool True if user has permission, otherwise false.
283334
*/
284335
private function can_user_sync_entity_type( string $entity_kind, string $entity_name, ?string $object_id ): bool {
285-
// Handle single post type entities with a defined object ID.
286-
if ( 'postType' === $entity_kind && is_numeric( $object_id ) ) {
287-
return current_user_can( 'edit_post', (int) $object_id );
336+
if ( is_string( $object_id ) ) {
337+
if ( ! ctype_digit( $object_id ) ) {
338+
return false;
339+
}
340+
$object_id = (int) $object_id;
288341
}
289-
290-
// Handle single taxonomy term entities with a defined object ID.
291-
if ( 'taxonomy' === $entity_kind && is_numeric( $object_id ) ) {
292-
$taxonomy = get_taxonomy( $entity_name );
293-
return isset( $taxonomy->cap->assign_terms ) && current_user_can( $taxonomy->cap->assign_terms );
342+
if ( null !== $object_id && $object_id <= 0 ) {
343+
// Object ID must be numeric if provided.
344+
return false;
294345
}
295346

296-
// Handle single comment entities with a defined object ID.
297-
if ( 'root' === $entity_kind && 'comment' === $entity_name && is_numeric( $object_id ) ) {
298-
return current_user_can( 'edit_comment', (int) $object_id );
347+
// Validate permissions for the provided object ID.
348+
if ( is_int( $object_id ) ) {
349+
// Handle single post type entities with a defined object ID.
350+
if ( 'postType' === $entity_kind ) {
351+
if ( get_post_type( $object_id ) !== $entity_name ) {
352+
// Post is not of the specified post type.
353+
return false;
354+
}
355+
return current_user_can( 'edit_post', $object_id );
356+
}
357+
358+
// Handle single taxonomy term entities with a defined object ID.
359+
if ( 'taxonomy' === $entity_kind ) {
360+
$term_exists = term_exists( $object_id, $entity_name );
361+
if ( ! is_array( $term_exists ) || ! isset( $term_exists['term_id'] ) ) {
362+
// Either term doesn't exist OR term is not in specified taxonomy.
363+
return false;
364+
}
365+
366+
return current_user_can( 'edit_term', $object_id );
367+
}
368+
369+
// Handle single comment entities with a defined object ID.
370+
if ( 'root' === $entity_kind && 'comment' === $entity_name ) {
371+
return current_user_can( 'edit_comment', $object_id );
372+
}
299373
}
300374

301375
// All the remaining checks are for collections. If an object ID is provided,

0 commit comments

Comments
 (0)