feat(deploy): preflight + smoke-test + UAT checklist (phases 3.9.1–3.11)

Prepare the project for production deployment and final client
acceptance testing. Adds preflight fail-fast command, hardened FX rate
importer, currency seeder, deploy scripts, E2E smoke test, and the
43-item UAT checklist document with sign-off form.

Key changes:

- Phase 3.9.1 — hotfix (AddressBookEntry):
  - Add $attributes defaults (use_count=0, is_default=false) so
    instance values are populated right after create() without
    refresh(). Resolves the red test
    `it_increments_use_count_and_sets_last_used_at`.

- Phase 3.10 — deploy infrastructure (Laravel):
  - Add `ifnex:preflight` command: fail-fast audit of production
    environment (APP_ENV, APP_DEBUG, APP_KEY, IFNEX_API_KEY,
    IFNEX_BRIDGE_API_KEY, ZARINPAL_SANDBOX, DB_CONNECTION, CORS,
    currencies seeded, PHP extensions, storage writable). Exits 1
    if any check fails; supports --skip-db for pre-migrate runs.
  - Add `ifnex:import-fx-rates` command: replacement for
    `ifnex:update-rates`. Fetches USD/AED from Exir.io + EUR/CNY
    from FreeCurrencyAPI. Supports --auto-approve (cron use) and
    --threshold (max change % for auto-approve). Logs critical on
    HTTP failure. URL configurable via EXIR_API_URL env.
  - Add `CurrencySeeder`: creates 5 base currencies (USD/AED/EUR/
    CNY/IRR) with rate=0 (IRR=1). Idempotent — does not overwrite
    real rates already set by admin or cron.
  - Update `DatabaseSeeder`: skip super_admin with password
    'password' in production (still created in local/testing).
  - Fix `bootstrap/app.php`: remove dead `use ApiKeyAuth` import
    (actual class is ApiKeyMiddleware). Latent fatal if api_key
    alias was used.
  - Add `config/ifnex.php` exir block + preflight config.
  - Harden `.env.example`: MySQL default, EXIR_API_URL,
    SANCTUM_STATEFUL_DOMAINS, APP_TIMEZONE, LOG_DAILY_DAYS, fix
    duplicate CURRENCY_API_KEY.

- Phase 3.10 — deploy scripts (Linux):
  - Add `scripts/deploy.sh`: idempotent 13-step deploy (composer
    install → key:generate → preflight → migrate → seed → FX import
    → cache → chown). Fail-fast with set -e.
  - Add `scripts/cron-exir-rates.sh`: daily cron wrapper for
    `ifnex:import-fx-rates --source=all --auto-approve`.

- Phase 3.10.1 — preflight hotfix:
  - Make expected DB connection configurable
    (ifnex.preflight.expected_db_connection) instead of hardcoded
    'mysql'. Prevents cascade test failure when tests would have to
    mutate database.default to mysql in a sqlite test environment
    (Unknown database ':memory:' → broken connection pool → 22
    previously-green tests fail with "There is already an active
    transaction").
  - Rewrite IfnexPreflightTest to use config() rather than mutating
    database.default.

- Phase 3.11 — UAT:
  - Add `ifnex:smoke-test` command: E2E post-deploy automated test
    (25+ checks: DB connection, core tables, currencies with
    non-zero rates, countries count, roles, admin user, system
    settings, storage writable, config/route cache, 4 API
    endpoints: /up, /countries, /track/{invalid}, /customer/profile
    without token).
  - Add 9 feature tests for smoke-test (PASS + 6 FAIL + custom URL
    + 422/500 handling + auth bypass detection).
  - Add `UAT-3.11.md`: 43-item Persian checklist for client
    acceptance testing across 15 feature areas. Includes sign-off
    form for both parties (client + VernaSoft).
  - Update `CLIENT_DELIVERY.md` to record phases 3.10 and 3.11.

Tests:
- Total: 51 → 82 tests, 150 → 220+ assertions, all green.
- New: IfnexPreflightTest (9), IfnexImportFxRatesTest (9),
  CurrencySeederTest (4), IfnexSmokeTestTest (9) = 31 new tests.

Documentation:
- DEPLOYMENT_HANDOFF.md §2.4: add CurrencySeeder + import-fx-rates.
- DEPLOYMENT_HANDOFF.md §2.8: update cron to use cron-exir-rates.sh.
- UAT-3.11.md: new 43-item client acceptance checklist + sign-off.
- CLIENT_DELIVERY.md: record phases 3.10 and 3.11 completion.
This commit is contained in:
Kazem Alghasi 2026-10-31 22:18:15 +03:30
parent a4fc807160
commit f1d5667fe8
134 changed files with 8773 additions and 5734 deletions

View File

@ -58,6 +58,102 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
<a href="contribute.php" class="nav-tab"><?php _e( 'Get Involved' ); ?></a>
</nav>
<div class="about__section changelog has-subtle-background-color">
<div class="column">
<h2><?php _e( 'Maintenance and Security Releases' ); ?></h2>
<p>
<?php
printf(
/* translators: %s: WordPress version. */
__( '<strong>Version %s</strong> addressed some security issues.' ),
'7.1.4'
);
?>
<?php
printf(
/* translators: %s: HelpHub URL. */
__( 'For more information, see <a href="%s">the release notes</a>.' ),
sprintf(
/* translators: %s: WordPress version. */
esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ),
sanitize_title( '7.1.4' )
)
);
?>
</p>
<p>
<?php
printf(
/* translators: 1: WordPress version number, 2: Plural number of bugs. */
_n(
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.',
4
),
'7.1.3',
'4'
);
?>
<?php
printf(
/* translators: %s: HelpHub URL. */
__( 'For more information, see <a href="%s">the release notes</a>.' ),
sprintf(
/* translators: %s: WordPress version. */
esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ),
sanitize_title( '7.1.3' )
)
);
?>
</p>
<p>
<?php
printf(
/* translators: %s: WordPress version. */
__( '<strong>Version %s</strong> addressed one security issue.' ),
'7.1.2'
);
?>
<?php
printf(
/* translators: %s: HelpHub URL. */
__( 'For more information, see <a href="%s">the release notes</a>.' ),
sprintf(
/* translators: %s: WordPress version. */
esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ),
sanitize_title( '7.1.2' )
)
);
?>
</p>
<p>
<?php
printf(
/* translators: 1: WordPress version number, 2: Plural number of bugs. More than one security issue. */
_n(
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
'<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.',
36
),
'7.1.1',
number_format_i18n( 36 )
);
?>
<?php
printf(
/* translators: %s: HelpHub URL. */
__( 'For more information, see <a href="%s">the release notes</a>.' ),
sprintf(
/* translators: %s: WordPress version. */
esc_url( __( 'https://wordpress.org/documentation/wordpress-version/version-%s/' ) ),
sanitize_title( '7.1.1' )
)
);
?>
</p>
</div>
</div>
<div class="about__section">
<div class="column is-left-padding-zero is-right-padding-zero">
<h2><?php _e( 'Welcome to WordPress 7.1' ); ?></h2>

View File

@ -1981,7 +1981,8 @@ div.action-links,
.plugins .active th.check-column,
.plugins .active td.check-column,
.plugin-update-tr.active td {
.plugin-update-tr.active td,
.plugins tr.paused td.check-column {
border-right: 4px solid transparent;
}
@ -1995,6 +1996,10 @@ div.action-links,
border-right: 4px solid var(--wp-admin-theme-color);
}
.plugins tr.active.paused {
border-right: 4px solid #b32d2e;
}
.wp-list-table .column-primary .toggle-row {
display: block;
}
@ -2341,8 +2346,7 @@ div.action-links,
.plugins tr.active + tr.inactive th.check-column,
.plugins tr.active + tr.inactive td.check-column,
.plugins tr.active + tr.inactive td.column-description,
.plugins .plugin-update-tr:before {
.plugins tr.active + tr.inactive td.column-description {
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1);
}
@ -2352,13 +2356,8 @@ div.action-links,
border-top: none;
}
/* mimic the checkbox th */
.plugins .plugin-update-tr:before {
content: "";
display: table-cell;
}
.plugins #the-list .plugin-update-tr .plugin-update {
flex: 0 1 100%;
border-right: none;
}
@ -2366,12 +2365,6 @@ div.action-links,
margin-right: 0;
}
.plugins .active.update + .plugin-update-tr:before,
.plugins .active.updated + .plugin-update-tr:before {
background-color: rgba(var(--wp-admin-theme-color--rgb), 0.08);
border-right: 4px solid var(--wp-admin-theme-color);
}
.plugins .plugin-update-tr .update-message {
margin-right: 0;
}

File diff suppressed because one or more lines are too long

View File

@ -1980,7 +1980,8 @@ div.action-links,
.plugins .active th.check-column,
.plugins .active td.check-column,
.plugin-update-tr.active td {
.plugin-update-tr.active td,
.plugins tr.paused td.check-column {
border-left: 4px solid transparent;
}
@ -1994,6 +1995,10 @@ div.action-links,
border-left: 4px solid var(--wp-admin-theme-color);
}
.plugins tr.active.paused {
border-left: 4px solid #b32d2e;
}
.wp-list-table .column-primary .toggle-row {
display: block;
}
@ -2340,8 +2345,7 @@ div.action-links,
.plugins tr.active + tr.inactive th.check-column,
.plugins tr.active + tr.inactive td.check-column,
.plugins tr.active + tr.inactive td.column-description,
.plugins .plugin-update-tr:before {
.plugins tr.active + tr.inactive td.column-description {
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1);
}
@ -2351,13 +2355,8 @@ div.action-links,
border-top: none;
}
/* mimic the checkbox th */
.plugins .plugin-update-tr:before {
content: "";
display: table-cell;
}
.plugins #the-list .plugin-update-tr .plugin-update {
flex: 0 1 100%;
border-left: none;
}
@ -2365,12 +2364,6 @@ div.action-links,
margin-left: 0;
}
.plugins .active.update + .plugin-update-tr:before,
.plugins .active.updated + .plugin-update-tr:before {
background-color: rgba(var(--wp-admin-theme-color--rgb), 0.08);
border-left: 4px solid var(--wp-admin-theme-color);
}
.plugins .plugin-update-tr .update-message {
margin-left: 0;
}

File diff suppressed because one or more lines are too long

View File

@ -202,11 +202,23 @@ p {
}
.login form .forgetmenot {
display: flex;
align-items: center;
gap: 4px;
/* Matches the height of the Log In button beside it, so the row centers on it. */
min-height: 40px;
font-weight: 400;
float: right;
margin-bottom: 0;
}
/* Centering aligns margin boxes, so margins left from the inline layout would offset these. */
.login form .forgetmenot input[type="checkbox"],
.login form .forgetmenot label {
margin-top: 0;
margin-bottom: 0;
}
.login .button-primary {
float: left;
}

File diff suppressed because one or more lines are too long

View File

@ -201,11 +201,23 @@ p {
}
.login form .forgetmenot {
display: flex;
align-items: center;
gap: 4px;
/* Matches the height of the Log In button beside it, so the row centers on it. */
min-height: 40px;
font-weight: 400;
float: left;
margin-bottom: 0;
}
/* Centering aligns margin boxes, so margins left from the inline layout would offset these. */
.login form .forgetmenot input[type="checkbox"],
.login form .forgetmenot label {
margin-top: 0;
margin-bottom: 0;
}
.login .button-primary {
float: right;
}

File diff suppressed because one or more lines are too long

View File

@ -1804,7 +1804,7 @@ function wp_ajax_add_user( $action ) {
'show-link' => sprintf(
/* translators: %s: The new user. */
__( 'User %s added' ),
'<a href="#user-' . $user_id . '">' . $user_object->user_login . '</a>'
'<a href="#user-' . $user_id . '">' . esc_html( $user_object->user_login ) . '</a>'
),
'role' => $role,
),
@ -2059,6 +2059,13 @@ function wp_ajax_menu_quick_search() {
function wp_ajax_get_permalink() {
check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
$post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0;
if ( ! $post_id ) {
// Bypass call to get_preview_post_link() for unspecified post ID.
wp_die( '' );
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
wp_die( -1 );
}
wp_die( get_preview_post_link( $post_id ) );
}
@ -2070,8 +2077,15 @@ function wp_ajax_get_permalink() {
function wp_ajax_sample_permalink() {
check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
$post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0;
$title = $_POST['new_title'] ?? '';
$slug = $_POST['new_slug'] ?? null;
if ( ! $post_id ) {
// Bypass call to get_sample_permalink_html() for unspecified post ID.
wp_die( '' );
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
wp_die( -1 );
}
$title = $_POST['new_title'] ?? '';
$slug = $_POST['new_slug'] ?? null;
wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
}
@ -4615,6 +4629,12 @@ function wp_ajax_activate_plugin() {
wp_send_json_error( $status );
}
// A network-only plugin is activated for the entire network.
if ( is_multisite() && is_network_only_plugin( $status['plugin'] ) && ! current_user_can( 'manage_network_plugins' ) ) {
$status['errorMessage'] = __( 'Sorry, you are not allowed to activate this plugin.' );
wp_send_json_error( $status );
}
if ( is_plugin_active( $status['plugin'] ) ) {
$status['errorMessage'] = sprintf(
/* translators: %s: Plugin name. */

View File

@ -572,7 +572,7 @@ class Custom_Image_Header {
$header_image_style .= 'height:' . $custom_header->height . 'px;';
}
?>
<div id="headimg" style="<?php echo $header_image_style; ?>">
<div id="headimg" style="<?php echo esc_attr( $header_image_style ); ?>">
<?php
if ( display_header_text() ) {
$style = ' style="color:#' . get_header_textcolor() . ';"';
@ -1184,8 +1184,8 @@ endif;
'attachment_id' => $choice['attachment_id'],
'url' => $choice['url'],
'thumbnail_url' => $choice['url'],
'height' => $choice['height'],
'width' => $choice['width'],
'height' => absint( $choice['height'] ),
'width' => absint( $choice['width'] ),
);
update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
@ -1216,7 +1216,13 @@ endif;
}
}
set_theme_mod( 'header_image', sanitize_url( $header_image_data['url'] ) );
$header_image_data['url'] = sanitize_url( $header_image_data['url'] );
if ( isset( $header_image_data['thumbnail_url'] ) ) {
$header_image_data['thumbnail_url'] = sanitize_url( $header_image_data['thumbnail_url'] );
}
set_theme_mod( 'header_image', $header_image_data['url'] );
set_theme_mod( 'header_image_data', $header_image_data );
}
@ -1589,9 +1595,8 @@ endif;
$alt_text_key = '_wp_attachment_image_alt';
foreach ( $header_images as &$header_image ) {
$header_meta = get_post_meta( $header_image['attachment_id'] );
$header_image['timestamp'] = $header_meta[ $timestamp_key ] ?? '';
$header_image['alt_text'] = $header_meta[ $alt_text_key ] ?? '';
$header_image['timestamp'] = get_post_meta( $header_image['attachment_id'], $timestamp_key, true );
$header_image['alt_text'] = get_post_meta( $header_image['attachment_id'], $alt_text_key, true );
}
return $header_images;

View File

@ -240,7 +240,7 @@ class WP_MS_Users_List_Table extends WP_List_Table {
<span class="screen-reader-text">
<?php
/* translators: Hidden accessibility text. %s: User login. */
printf( __( 'Select %s' ), $user->user_login );
printf( __( 'Select %s' ), esc_html( $user->user_login ) );
?>
</span>
</label>
@ -273,9 +273,9 @@ class WP_MS_Users_List_Table extends WP_List_Table {
if ( current_user_can( 'edit_user', $user->ID ) ) {
$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
$edit = "<a href=\"{$edit_link}\">{$user->user_login}</a>";
$edit = "<a href=\"{$edit_link}\">" . esc_html( $user->user_login ) . '</a>';
} else {
$edit = $user->user_login;
$edit = esc_html( $user->user_login );
}
?>

View File

@ -98,7 +98,7 @@ class WP_Privacy_Data_Export_Requests_List_Table extends WP_Privacy_Requests_Tab
$row_actions['complete-request'] = $complete_request_markup;
}
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), esc_html( $item->email ), $this->row_actions( $row_actions ) );
}
/**

View File

@ -104,7 +104,7 @@ class WP_Privacy_Data_Removal_Requests_List_Table extends WP_Privacy_Requests_Ta
$row_actions['complete-request'] = $complete_request_markup;
}
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), esc_html( $item->email ), $this->row_actions( $row_actions ) );
}
/**

View File

@ -425,7 +425,7 @@ abstract class WP_Privacy_Requests_Table extends WP_List_Table {
'<label for="requester_%1$s"><span class="screen-reader-text">%2$s</span></label><span class="spinner"></span>',
esc_attr( $item->ID ),
/* translators: Hidden accessibility text. %s: Email address. */
sprintf( __( 'Select %s' ), $item->email )
sprintf( __( 'Select %s' ), esc_html( $item->email ) )
);
}
@ -551,7 +551,7 @@ abstract class WP_Privacy_Requests_Table extends WP_List_Table {
* @return string Email column markup.
*/
public function column_email( $item ) {
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) );
return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), esc_html( $item->email ), $this->row_actions( array() ) );
}
/**

View File

@ -343,6 +343,21 @@ class WP_Upgrader {
return $download_file;
}
/**
* Builds an unpredictable name for the directory a package is unpacked into.
*
* @since 7.1.4
*
* @param string $package The full local path or URI of the package.
* @return string The directory name, without a path.
*/
private function get_working_dir_name( $package ) {
// Strip off any .tmp or .zip suffixes.
$name = basename( basename( $package, '.tmp' ), '.zip' );
return $name . '-' . wp_generate_password( 16, false );
}
/**
* Unpacks a compressed package file.
*
@ -366,16 +381,32 @@ class WP_Upgrader {
$upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
// Clean up contents of upgrade directory beforehand.
// Clean up contents of upgrade directory beforehand, keeping its index.php.
$upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
if ( ! empty( $upgrade_files ) ) {
foreach ( $upgrade_files as $file ) {
if ( 'index.php' === $file['name'] ) {
continue;
}
$wp_filesystem->delete( $upgrade_folder . $file['name'], true );
}
}
// We need a working directory - strip off any .tmp or .zip suffixes.
$working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
/*
* The upgrade directory is web-served. Keep it from being listed, as core does
* for wp-content and its plugins and themes directories, so the name of the
* working directory created below cannot be discovered from a directory index.
*/
if ( ! $wp_filesystem->is_dir( $upgrade_folder ) ) {
$wp_filesystem->mkdir( $upgrade_folder, FS_CHMOD_DIR );
}
if ( ! $wp_filesystem->exists( $upgrade_folder . 'index.php' ) ) {
$wp_filesystem->put_contents( $upgrade_folder . 'index.php', "<?php\n// Silence is golden.\n", FS_CHMOD_FILE );
}
// We need a working directory.
$working_dir = $upgrade_folder . $this->get_working_dir_name( $package );
// Clean up working directory.
if ( $wp_filesystem->is_dir( $working_dir ) ) {

View File

@ -468,10 +468,10 @@ class WP_Users_List_Table extends WP_List_Table {
);
if ( current_user_can( 'edit_user', $user_object->ID ) ) {
$edit = "<strong><a href=\"{$edit_link}\">{$user_object->user_login}</a>{$super_admin}</strong><br />";
$edit = '<strong><a href="' . $edit_link . '">' . esc_html( $user_object->user_login ) . "</a>{$super_admin}</strong><br />";
$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
} else {
$edit = "<strong>{$user_object->user_login}{$super_admin}</strong><br />";
$edit = '<strong>' . esc_html( $user_object->user_login ) . "{$super_admin}</strong><br />";
}
if ( ! is_multisite()
@ -529,11 +529,11 @@ class WP_Users_List_Table extends WP_List_Table {
$user_object->ID,
$role_classes,
/* translators: Hidden accessibility text. %s: User login. */
sprintf( __( 'Select %s' ), $user_object->user_login )
sprintf( __( 'Select %s' ), esc_html( $user_object->user_login ) )
);
} else {
$edit = "<strong>{$user_object->user_login}{$super_admin}</strong>";
$edit = '<strong>' . esc_html( $user_object->user_login ) . "{$super_admin}</strong>";
}
$avatar = get_avatar( $user_object->ID, 32 );

View File

@ -183,11 +183,15 @@ function export_wp( $args = array() ) {
)
);
// Cast thumbnail IDs to integers to prevent second-order SQL injection via user-controlled meta values.
$thumbnails_ids = array_filter( array_map( 'absint', $thumbnails_ids ) );
$additional_ids = array_merge( $additional_ids, $attachment_ids, $thumbnails_ids );
}
// Merge the additional IDs back with the original post IDs after processing all posts
$post_ids = array_unique( array_merge( $post_ids, $additional_ids ) );
// Merge the additional IDs back with the original post IDs after processing all posts.
// Cast to integers as defense-in-depth, since $additional_ids may include values sourced from postmeta.
$post_ids = array_unique( array_map( 'absint', array_merge( $post_ids, $additional_ids ) ) );
}
/*
@ -597,8 +601,10 @@ function export_wp( $args = array() ) {
// Fetch 20 posts at a time rather than loading the entire table into memory.
while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) {
$where = 'WHERE ID IN (' . implode( ',', $next_posts ) . ')';
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
// Re-sanitize immediately before use, as defense-in-depth against the IDs being interpolated directly into SQL below.
$next_posts = array_map( 'absint', $next_posts );
$where = 'WHERE ID IN (' . implode( ',', $next_posts ) . ')';
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
// Begin Loop.
foreach ( $posts as $post ) {

View File

@ -1083,10 +1083,15 @@ function wp_read_image_metadata( $file ) {
* @since 7.0.0
*
* @param string $file File path to the image.
* @return string Embedded alternative text.
* @return string Embedded alternative text, empty when there is no alt text or DOM extension is not installed.
*/
function wp_get_image_alttext( $file ) {
$alt_text = '';
$alt_text = '';
if ( ! class_exists( 'DOMDocument', false ) ) {
return $alt_text;
}
$img_contents = file_get_contents( $file );
if ( false === $img_contents ) {

View File

@ -3370,7 +3370,7 @@ function attachment_submitbox_metadata() {
<?php
if ( $post->post_parent ) {
$post_parent = get_post( $post->post_parent );
if ( $post_parent ) {
if ( $post_parent && current_user_can( 'read_post', $post_parent->ID ) ) {
$uploaded_to_title = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' );
$uploaded_to_link = get_edit_post_link( $post->post_parent, 'raw' );
?>

View File

@ -889,7 +889,7 @@ function confirm_delete_users( $users ) {
sprintf(
/* translators: %s: User login. */
__( 'Warning! User %s cannot be deleted.' ),
$delete_user->user_login
esc_html( $delete_user->user_login )
)
);
}
@ -899,14 +899,14 @@ function confirm_delete_users( $users ) {
sprintf(
/* translators: %s: User login. */
__( 'Warning! User cannot be deleted. The user %s is a network administrator.' ),
'<em>' . $delete_user->user_login . '</em>'
'<em>' . esc_html( $delete_user->user_login ) . '</em>'
)
);
}
?>
<tr>
<th scope="row"><?php echo $delete_user->user_login; ?>
<th scope="row"><?php echo esc_html( $delete_user->user_login ); ?>
<?php echo '<input type="hidden" name="user[]" value="' . esc_attr( $user_id ) . '" />' . "\n"; ?>
</th>
<?php
@ -919,7 +919,7 @@ function confirm_delete_users( $users ) {
printf(
/* translators: 1: User login, 2: User ID. */
__( '%1$s (ID #%2$s): What should be done with the content owned by this user?' ),
'<strong>' . $delete_user->user_login . '</strong>',
'<strong>' . esc_html( $delete_user->user_login ) . '</strong>',
$user_id
);
?>
@ -1003,6 +1003,7 @@ function confirm_delete_users( $users ) {
'include' => $blog_users,
'show' => 'display_name_with_login',
'id' => "reassign_user_{$details->userblog_id}_{$delete_user->ID}",
'blog_id' => $details->userblog_id,
)
);
?>

View File

@ -598,11 +598,17 @@ function is_plugin_active_for_network( $plugin ) {
* Checks for "Site Wide Only: true" for backward compatibility.
*
* @since 3.0.0
* @since 7.1.1 The `$plugin` path is normalized with `plugin_basename()` and `trim()`,
* matching how `activate_plugin()` resolves it.
*
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param string $plugin Path to the plugin file. Accepts a path relative to the plugins
* directory, or an absolute path, with or without surrounding whitespace.
* @return bool True if plugin is network only, false otherwise.
*/
function is_network_only_plugin( $plugin ) {
// Normalize the path the same way activate_plugin() does, so both agree on the file.
$plugin = plugin_basename( trim( $plugin ) );
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
if ( $plugin_data ) {
return $plugin_data['Network'];

View File

@ -24,6 +24,20 @@ function _wp_translate_postdata( $update = false, $post_data = null ) {
$post_data = &$_POST;
}
/*
* A raw `ID` on the create path (no `post_ID`) is an attempt to overwrite an
* existing post while bypassing the per-post capability checks below, which only
* run on the update path. Reject it outright: legitimate post creation never
* carries an `ID`.
*/
if ( ! $update && ! empty( $post_data['ID'] ) ) {
if ( 'page' === $post_data['post_type'] ) {
return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) );
} else {
return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) );
}
}
if ( $update ) {
$post_data['ID'] = (int) $post_data['post_ID'];
}

View File

@ -1545,8 +1545,9 @@ function update_core( $from, $to ) {
/*
* Don't copy wp-content, we'll deal with that below.
* We also copy version.php last so failed updates report their old version.
* Never copy a wp-config.php, which could have been written to the working directory.
*/
$skip = array( 'wp-content', 'wp-includes/version.php' );
$skip = array( 'wp-content', 'wp-includes/version.php', 'wp-config.php' );
$check_is_writable = array();
// Check to see which files don't really need updating - only available for 3.7 and higher.

View File

@ -695,7 +695,7 @@ $('.contextual-help-tabs').on( 'click', 'a', function(e) {
$('.contextual-help-tabs .active').removeClass('active');
link.parent('li').addClass('active');
panel = $( link.attr('href') );
panel = $( document ).find( link.attr('href') );
// Panels.
$('.help-tab-content').not( panel ).removeClass('active').hide();

File diff suppressed because one or more lines are too long

View File

@ -2082,9 +2082,9 @@ themes.RunInstaller = {
self.view.collection.query( request );
self.view.collection.trigger( 'update' );
// Open the theme preview.
// Open the theme preview. The slug comes from the URL, so escape it.
self.view.collection.once( 'query:success', function() {
$( 'div[data-slug="' + slug + '"]' ).trigger( 'click' );
$( 'div.theme[data-slug="' + $.escapeSelector( slug ) + '"]' ).trigger( 'click' );
});
}

File diff suppressed because one or more lines are too long

View File

@ -557,7 +557,7 @@ switch ( $action ) {
?>
<?php foreach ( $public_display as $id => $item ) : ?>
<option <?php selected( $profile_user->display_name, $item ); ?>><?php echo $item; ?></option>
<option <?php selected( $profile_user->display_name, $item ); ?>><?php echo esc_html( $item ); ?></option>
<?php endforeach; ?>
</select>
</td>
@ -790,7 +790,7 @@ switch ( $action ) {
<p class="description">
<?php
/* translators: %s: User's display name. */
printf( __( 'Log %s out of all locations.' ), $profile_user->display_name );
printf( __( 'Log %s out of all locations.' ), esc_html( $profile_user->display_name ) );
?>
</p>
</td>

View File

@ -351,7 +351,7 @@ switch ( $wp_list_table->current_action() ) {
/* translators: 1: User ID, 2: User login. */
__( 'ID #%1$s: %2$s <strong>The current user will not be deleted.</strong>' ),
$id,
$user->user_login
esc_html( $user->user_login )
);
echo "</li>\n";
} else {
@ -402,7 +402,7 @@ switch ( $wp_list_table->current_action() ) {
printf(
/* translators: 1: User login. 2: User ID */
__( '%1$s (ID #%2$s): This user does not have any content.' ),
'<strong>' . $user->user_login . '</strong>',
'<strong>' . esc_html( $user->user_login ) . '</strong>',
$id
);
?>
@ -416,7 +416,7 @@ switch ( $wp_list_table->current_action() ) {
printf(
/* translators: 1: User login, 2: User ID. */
__( '%1$s (ID #%2$s): What should be done with the content owned by this user?' ),
'<strong>' . $user->user_login . '</strong>',
'<strong>' . esc_html( $user->user_login ) . '</strong>',
$id
);
?>
@ -568,7 +568,7 @@ switch ( $wp_list_table->current_action() ) {
/* translators: 1: User ID, 2: User login. */
__( 'ID #%1$s: %2$s <strong>Sorry, you are not allowed to remove this user.</strong>' ),
$id,
$user->user_login
esc_html( $user->user_login )
);
echo "</li>\n";
} else {
@ -581,7 +581,7 @@ switch ( $wp_list_table->current_action() ) {
/* translators: 1: User ID, 2: User login. */
__( 'ID #%1$s: %2$s' ),
$id,
$user->user_login
esc_html( $user->user_login )
);
echo "</li>\n";

View File

@ -274,7 +274,7 @@ function wp_admin_bar_my_account_item( $wp_admin_bar ) {
}
/* translators: %s: Current user's display name. */
$howdy = sprintf( __( 'Howdy, %s' ), '<span class="display-name">' . wp_get_current_user()->display_name . '</span>' );
$howdy = sprintf( __( 'Howdy, %s' ), '<span class="display-name">' . esc_html( wp_get_current_user()->display_name ) . '</span>' );
$avatar = get_avatar( $user_id, 28 );
$wp_admin_bar->add_node(
@ -323,10 +323,10 @@ function wp_admin_bar_my_account_menu( $wp_admin_bar ) {
);
$user_info = get_avatar( $user_id, 64 );
$user_info .= "<span class='display-name'>{$current_user->display_name}</span>";
$user_info .= "<span class='display-name'>" . esc_html( $current_user->display_name ) . '</span>';
if ( $current_user->display_name !== $current_user->user_login ) {
$user_info .= "<span class='username'>{$current_user->user_login}</span>";
$user_info .= "<span class='username'>" . esc_html( $current_user->user_login ) . '</span>';
}
if ( false !== $profile_url ) {

View File

@ -104,7 +104,7 @@
'wp-url',
'wp-warning'
),
'version' => 'd3cbb2c45b145b27a5cf'
'version' => '37e58da384b2558bd479'
),
'block-library.js' => array(
'dependencies' => array(
@ -150,19 +150,19 @@
'import' => 'dynamic'
)
),
'version' => '2e80403676c10cc0a473'
'version' => '00e6e2a44788af201f35'
),
'block-serialization-default-parser.js' => array(
'dependencies' => array(
),
'version' => '4c6f3dd40077f7c17604'
'version' => 'fc209395a022242d64aa'
),
'block-serialization-spec-parser.js' => array(
'dependencies' => array(
),
'version' => '7b0b496c3d48b1ef3f9e'
'version' => '345804e2c9fb36e816cd'
),
'blocks.js' => array(
'dependencies' => array(
@ -402,7 +402,7 @@
'import' => 'static'
)
),
'version' => 'a7750dea8d5c880ddf33'
'version' => 'a6cb1641d13f718c01bd'
),
'edit-site.js' => array(
'dependencies' => array(
@ -452,7 +452,7 @@
'import' => 'static'
)
),
'version' => '638e98d0061f4b9f1efb'
'version' => '008f89f2cb2ad17a5947'
),
'edit-widgets.js' => array(
'dependencies' => array(
@ -543,7 +543,7 @@
'import' => 'static'
)
),
'version' => '2cd3b932f41a420d5904'
'version' => 'af070cfff88093363220'
),
'element.js' => array(
'dependencies' => array(
@ -663,7 +663,7 @@
'wp-url',
'wp-warning'
),
'version' => 'b8bf604c1cc119e63ee6'
'version' => '07c1c94f9b21baa97a96'
),
'notices.js' => array(
'dependencies' => array(
@ -881,7 +881,7 @@
'import' => 'dynamic'
)
),
'version' => 'f7174b0617bcd68e57c3'
'version' => 'a2c026d433c295fd5145'
),
'url.js' => array(
'dependencies' => array(

View File

@ -64,7 +64,7 @@
'import' => 'static'
)
),
'version' => '25ee935fd6c67371d0f3'
'version' => '25f29e3c6cc00370914b'
),
'block-library/navigation/view.js' => array(
'dependencies' => array(
@ -253,7 +253,7 @@
'dependencies' => array(
),
'version' => 'efaa5193bbad9c60ffd1'
'version' => '6a43cba92ed701f32cd9'
),
'interactivity-router/full-page.js' => array(
'dependencies' => array(
@ -281,7 +281,7 @@
'import' => 'static'
)
),
'version' => 'a6e90b8896f83fb1b5dd'
'version' => 'dea5032c2153d213c1ee'
),
'latex-to-mathml/index.js' => array(
'dependencies' => array(
@ -360,7 +360,7 @@
'dependencies' => array(
),
'version' => '685442d334b2d3e70832'
'version' => '7e33cd8c4128731126e8'
),
'workflow/index.js' => array(
'dependencies' => array(

View File

@ -542,6 +542,16 @@ function wp_render_block_states_support( $block_content, $block ) {
return $block_content;
}
/*
* Every CSS rule this function can produce is keyed off the block's `style`
* attribute. Without it there is nothing to generate, so bail before doing
* any of the lookups below — this runs for every block on every request.
*/
$style = $block['attrs']['style'] ?? array();
if ( empty( $style ) || ! is_array( $style ) ) {
return $block_content;
}
$block_name = $block['blockName'];
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name );
if ( ! $block_type ) {
@ -549,7 +559,6 @@ function wp_render_block_states_support( $block_content, $block ) {
}
$supported_pseudo_states = WP_Theme_JSON::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] ?? array();
$style = $block['attrs']['style'] ?? array();
$css_rules = array();
$viewport_settings = wp_get_global_settings( array( 'viewport' ) );
$responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings );

View File

@ -343,11 +343,22 @@ function _get_block_template_file( $template_type, $slug ) {
);
foreach ( $themes as $theme_slug => $theme_dir ) {
$template_base_paths = get_block_theme_folders( $theme_slug );
$file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html';
if ( file_exists( $file_path ) ) {
$template_dir = $theme_dir . '/' . $template_base_paths[ $template_type ];
$file_path = $template_dir . '/' . $slug . '.html';
$template_file = realpath( $file_path );
$template_root = realpath( $template_dir );
if (
false !== $template_file &&
false !== $template_root &&
str_starts_with(
wp_normalize_path( $template_file ),
trailingslashit( wp_normalize_path( $template_root ) )
)
) {
$new_template_item = array(
'slug' => $slug,
'path' => $file_path,
'path' => $template_file,
'theme' => $theme_slug,
'type' => $template_type,
);

View File

@ -1,3 +1,6 @@
.wp-block-accordion-panel[hidden] {
border: none !important;
box-shadow: none !important;
margin-block-start: 0;
padding: 0 !important;
}

View File

@ -1 +1 @@
.wp-block-accordion-panel[hidden]{margin-block-start:0}
.wp-block-accordion-panel[hidden]{border:none!important;box-shadow:none!important;margin-block-start:0;padding:0!important}

View File

@ -1,3 +1,6 @@
.wp-block-accordion-panel[hidden] {
border: none !important;
box-shadow: none !important;
margin-block-start: 0;
padding: 0 !important;
}

View File

@ -1 +1 @@
.wp-block-accordion-panel[hidden]{margin-block-start:0}
.wp-block-accordion-panel[hidden]{border:none!important;box-shadow:none!important;margin-block-start:0;padding:0!important}

View File

@ -53,7 +53,7 @@ function render_block_core_categories( $attributes, $content, $block ) {
$show_label = empty( $attributes['showLabel'] ) ? ' screen-reader-text' : '';
$default_label = $taxonomy->label;
$label_text = ! empty( $attributes['label'] ) ? wp_kses_post( $attributes['label'] ) : $default_label;
$wrapper_markup = '<div %1$s><label class="wp-block-categories__label' . $show_label . '" for="' . esc_attr( $id ) . '">' . $label_text . '</label>%2$s</div>';
$wrapper_markup = '<div %1$s><label class="wp-block-categories__label' . $show_label . '" for="' . esc_attr( $id ) . '">%3$s</label>%2$s</div>';
$items_markup = wp_dropdown_categories( $args );
$type = 'dropdown';
@ -69,6 +69,7 @@ function render_block_core_categories( $attributes, $content, $block ) {
} else {
$args['show_option_none'] = $taxonomy->labels->no_terms;
$label_text = '';
$wrapper_markup = '<ul %1$s>%2$s</ul>';
$items_markup = wp_list_categories( $args );
$type = 'list';
@ -87,7 +88,8 @@ function render_block_core_categories( $attributes, $content, $block ) {
return sprintf(
$wrapper_markup,
$wrapper_attributes,
$items_markup
$items_markup,
$label_text
);
}

View File

@ -25,7 +25,7 @@ function render_block_core_comments_pagination_next( $attributes, $content, $blo
$comment_vars = build_comment_query_vars_from_block( $block );
$max_page = ( new WP_Comment_Query( $comment_vars ) )->max_num_pages;
$default_label = __( 'Newer Comments' );
$label = isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$label = ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$pagination_arrow = get_comments_pagination_arrow( $block, 'next' );
$filter_link_attributes = static function () {
@ -33,6 +33,8 @@ function render_block_core_comments_pagination_next( $attributes, $content, $blo
};
add_filter( 'next_comments_link_attributes', $filter_link_attributes );
// Escaping early as the pagination arrow usually returns HTML and shouldn't be escaped.
$label = esc_html( $label );
if ( $pagination_arrow ) {
$label .= $pagination_arrow;
}

View File

@ -18,8 +18,11 @@
*/
function render_block_core_comments_pagination_previous( $attributes, $content, $block ) {
$default_label = __( 'Older Comments' );
$label = isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$label = ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label;
$pagination_arrow = get_comments_pagination_arrow( $block, 'previous' );
// Escaping early as pagination arrow can return HTML that should not be escaped.
$label = esc_html( $label );
if ( $pagination_arrow ) {
$label = $pagination_arrow . $label;
}

View File

@ -290,12 +290,8 @@ function block_core_image_render_lightbox( $block_content, array $block, WP_Bloc
$body_content = $processor->get_updated_html();
// Adds a button alongside image in the body content.
$img = null;
preg_match( '/<img[^>]+>/', $body_content, $img );
$button =
$img[0]
. '<button
'<button
class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
@ -310,7 +306,26 @@ function block_core_image_render_lightbox( $block_content, array $block, WP_Bloc
</svg>
</button>';
$body_content = preg_replace( '/<img[^>]+>/', $button, $body_content );
$button_processor = new class( $body_content ) extends WP_HTML_Tag_Processor {
/**
* Inserts HTML immediately after the current token.
*
* @since 7.1.4
*
* @param string $html HTML to insert.
*/
public function block_core_image_insert_after( string $html ) {
$this->set_bookmark( 'here' );
$span = $this->bookmarks['here'];
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $span->start + $span->length, 0, $html );
}
};
if ( $button_processor->next_tag( 'img' ) ) {
$button_processor->block_core_image_insert_after( $button );
}
$body_content = $button_processor->get_updated_html();
add_action( 'wp_footer', 'block_core_image_print_lightbox_overlay' );

View File

@ -140,33 +140,43 @@ function render_block_core_playlist( $attributes, $content, $block ) {
></div>';
// Add the waveform player container inside the figure.
$figure = null;
preg_match( '/<figure[^>]*>/', $content, $figure );
if ( ! empty( $figure[0] ) ) {
$content = preg_replace( '/(<figure[^>]*>)/', '$1' . $html, $content, 1 );
}
$processor = new class( $content ) extends WP_HTML_Tag_Processor {
/**
* Inserts HTML immediately after the current token.
*
* @since 7.1.4
*
* @param string $html HTML to insert.
*/
public function block_core_playlist_insert_after( string $html ) {
$this->set_bookmark( 'here' );
$span = $this->bookmarks['here'];
$processor = new WP_HTML_Tag_Processor( $content );
$processor->next_tag( 'figure' );
$processor->set_attribute( 'data-wp-interactive', 'core/playlist' );
$this->lexical_updates[] = new WP_HTML_Text_Replacement( $span->start + $span->length, 0, $html );
}
};
$waveform_style = $attributes['waveformStyle'] ?? 'bars';
$processor->set_attribute(
'data-wp-context',
wp_json_encode(
array(
'playlistId' => $playlist_id,
'currentId' => $playlist_tracks[0],
'isPlaying' => false,
'tracks' => $playlist_tracks,
'waveformStyle' => $waveform_style,
'showPlayButtonArtwork' => $show_play_button_artwork,
'labelPauseTrack' => __( 'Pause' ),
'labelSelectTrack' => __( 'Play' ),
if ( $processor->next_tag( 'figure' ) ) {
$processor->block_core_playlist_insert_after( $html );
$processor->set_attribute( 'data-wp-interactive', 'core/playlist' );
$processor->set_attribute(
'data-wp-context',
wp_json_encode(
array(
'playlistId' => $playlist_id,
'currentId' => $playlist_tracks[0],
'isPlaying' => false,
'tracks' => $playlist_tracks,
'waveformStyle' => $waveform_style,
'showPlayButtonArtwork' => $show_play_button_artwork,
'labelPauseTrack' => __( 'Pause' ),
'labelSelectTrack' => __( 'Play' ),
)
)
)
);
);
}
// Track IDs are render-time only. Add them after inner blocks have rendered
// so track buttons can update the Interactivity API state without storing

View File

@ -57,7 +57,7 @@ function render_block_core_post_navigation_link( $attributes, $content ) {
// `$label` is used to prepend the provided label, if we want to show the page title as well.
if ( isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ) {
$label = "{$attributes['label']}";
$link = $label;
$link = wp_kses_post( $label );
}
// If we want to also show the page title, make the page title a link and prepend the label.

View File

@ -310,6 +310,22 @@ function wp_font_library_render_page() {
function wp_font_library_intercept_render() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['page'] ) && 'font-library' === $_GET['page'] ) {
// The page renders outside the menu page callback flow, so it must
// enforce authentication and capability checks itself. Without this,
// any admin entry point firing `admin_init` (such as admin-post.php,
// which serves logged-out requests) would render the page for
// unauthenticated visitors.
if ( ! is_user_logged_in() ) {
auth_redirect();
}
if ( ! current_user_can( 'edit_theme_options' ) ) {
wp_die(
__( 'Sorry, you are not allowed to access this page.' ),
403
);
}
wp_font_library_render_page();
exit;
}

View File

@ -310,6 +310,22 @@ function wp_options_connectors_render_page() {
function wp_options_connectors_intercept_render() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['page'] ) && 'options-connectors' === $_GET['page'] ) {
// The page renders outside the menu page callback flow, so it must
// enforce authentication and capability checks itself. Without this,
// any admin entry point firing `admin_init` (such as admin-post.php,
// which serves logged-out requests) would render the page for
// unauthenticated visitors.
if ( ! is_user_logged_in() ) {
auth_redirect();
}
if ( ! current_user_can( 'manage_options' ) ) {
wp_die(
__( 'Sorry, you are not allowed to access this page.' ),
403
);
}
wp_options_connectors_render_page();
exit;
}

View File

@ -11645,14 +11645,15 @@ var GeminiLogo = () => /* @__PURE__ */ React.createElement(
var { store: connectorsStore } = unlock2(connectorsPrivateApis);
function getConnectorScriptModuleData() {
try {
return JSON.parse(
document.getElementById(
"wp-script-module-data-options-connectors-wp-admin"
)?.textContent ?? "{}"
const script = document.querySelector(
'script[id="wp-script-module-data-options-connectors-wp-admin"]'
);
if (script instanceof HTMLScriptElement) {
return JSON.parse(script.text);
}
} catch {
return {};
}
return {};
}
function getConnectorData() {
return getConnectorScriptModuleData().connectors ?? {};

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/connectors', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '1c478cb5cadaf4aded06');
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/connectors', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '2d1e1deff36091f228ab');

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -245,7 +245,7 @@ class WP_Block_Parser {
* match back in PHP to see which one it was.
*/
$has_match = preg_match(
'/<!--\s+(?P<closer>\/)?wp:(?P<namespace>[a-z][a-z0-9_-]*\/)?(?P<name>[a-z][a-z0-9_-]*)\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P<void>\/)?-->/s',
'/<!--[ \t\f\r\n]+(?P<closer>\/)?wp:(?P<namespace>[a-z][a-z0-9_-]*\/)?(?P<name>[a-z][a-z0-9_-]*)[ \t\f\r\n]+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}[ \t\f\r\n]+\/?-->).)*+)?}[ \t\f\r\n]+)?(?P<void>\/)?-->/s',
$this->document,
$matches,
PREG_OFFSET_CAPTURE,

View File

@ -628,7 +628,13 @@ final class WP_Customize_Manager {
if ( empty( $this->_changeset_uuid ) ) {
$changeset_uuid = null;
if ( ! $this->branching() && $this->is_theme_active() ) {
/**
* Only users who can customize may have the latest unpublished changeset auto-loaded. Otherwise, an
* unauthenticated preview request lacking a UUID could adopt another user's unpublished changeset and
* disclose its state, since the UUID serves as the secret key for previewing. Unauthorized requests
* get a fresh UUID instead, which matches no changeset and is rejected in {@see self::setup_theme()}.
*/
if ( ! $this->branching() && $this->is_theme_active() && current_user_can( 'customize' ) ) {
$unpublished_changeset_posts = $this->get_changeset_posts(
array(
'post_status' => array_diff( get_post_stati(), array( 'auto-draft', 'publish', 'trash', 'inherit', 'private' ) ),

View File

@ -20,8 +20,8 @@
* accepted_args: int,
* }
*
* @phpstan-implements Iterator<int, array<string, Hook_Callback>>
* @phpstan-implements ArrayAccess<int, array<string, Hook_Callback>>
* @phpstan-implements Iterator<int, array<non-decimal-int-string, Hook_Callback>>
* @phpstan-implements ArrayAccess<int, array<non-decimal-int-string, Hook_Callback>>
*/
#[AllowDynamicProperties]
final class WP_Hook implements Iterator, ArrayAccess {
@ -31,7 +31,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
*
* @since 4.7.0
* @var array
* @phpstan-var array<int, array<string, Hook_Callback>>
* @phpstan-var array<int, array<non-decimal-int-string, Hook_Callback>>
*/
public $callbacks = array();
@ -502,7 +502,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
*
* @param int $offset The offset to retrieve.
* @return array|null If set, the value at the specified offset, null otherwise.
* @phpstan-return array<string, Hook_Callback>|null
* @phpstan-return array<non-decimal-int-string, Hook_Callback>|null
*/
#[ReturnTypeWillChange]
public function offsetGet( $offset ) {
@ -518,7 +518,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
*
* @param int|null $offset The offset to assign the value to.
* @param array $value The value to set.
* @phpstan-param array<string, Hook_Callback> $value
* @phpstan-param array<non-decimal-int-string, Hook_Callback> $value
*/
#[ReturnTypeWillChange]
public function offsetSet( $offset, $value ) {
@ -554,7 +554,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
* @link https://www.php.net/manual/en/iterator.current.php
*
* @return array|false Array of callbacks at current priority, false if there are no more elements.
* @phpstan-return array<string, Hook_Callback>|false
* @phpstan-return array<non-decimal-int-string, Hook_Callback>|false
*/
#[ReturnTypeWillChange]
public function current() {
@ -569,7 +569,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
* @link https://www.php.net/manual/en/iterator.next.php
*
* @return array|false Array of callbacks at next priority, false if there are no more elements.
* @phpstan-return array<string, Hook_Callback>|false
* @phpstan-return array<non-decimal-int-string, Hook_Callback>|false
*/
#[ReturnTypeWillChange]
public function next() {

View File

@ -1023,7 +1023,10 @@ class WP_Http {
// Strip all /path/../ out of the path.
while ( strpos( $path, '../' ) > 1 ) {
$path = preg_replace( '![^/]+/\.\./!', '', $path );
$path = preg_replace( '![^/]+/\.\./!', '', $path, -1, $segment_replacement_count );
if ( 0 === $segment_replacement_count ) {
break;
}
}
// Strip any final leading ../ from the path.

View File

@ -79,7 +79,6 @@ class WP_oEmbed {
'#https?://(www\.)?twitter\.com/i/moments/.*#i' => array( 'https://publish.twitter.com/oembed', true ),
'#https?://(www\.)?soundcloud\.com/.*#i' => array( 'https://soundcloud.com/oembed', true ),
'#https?://(open|play)\.spotify\.com/.*#i' => array( 'https://embed.spotify.com/oembed/', true ),
'#https?://(.+\.)?imgur\.com/.*#i' => array( 'https://api.imgur.com/oembed', true ),
'#https?://(www\.)?issuu\.com/.+/docs/.+#i' => array( 'https://issuu.com/oembed_wp', true ),
'#https?://(www\.)?mixcloud\.com/.*#i' => array( 'https://app.mixcloud.com/oembed/', true ),
'#https?://(www\.|embed\.)?ted\.com/talks/.*#i' => array( 'https://www.ted.com/services/v1/oembed.{format}', true ),
@ -88,7 +87,7 @@ class WP_oEmbed {
'#https?://(www\.)?kickstarter\.com/projects/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ),
'#https?://kck\.st/.*#i' => array( 'https://www.kickstarter.com/services/oembed', true ),
'#https?://cloudup\.com/.*#i' => array( 'https://cloudup.com/oembed', true ),
'#https?://(www\.)?reverbnation\.com/.*#i' => array( 'https://www.reverbnation.com/oembed', true ),
'#https?://((legacy|www)\.)?reverbnation\.com/.*#i' => array( 'https://legacy.reverbnation.com/oembed', true ),
'#https?://videopress\.com/v/.*#' => array( 'https://public-api.wordpress.com/oembed/?for=' . $host, true ),
'#https?://(www\.)?reddit\.com/r/[^/]+/comments/.*#i' => array( 'https://www.reddit.com/oembed', true ),
'#https?://(www\.)?speakerdeck\.com/.*#i' => array( 'https://speakerdeck.com/oembed.{format}', true ),
@ -102,9 +101,6 @@ class WP_oEmbed {
'#https?://(www\.)?amzn\.in/.*#i' => array( 'https://read.amazon.in/kp/api/oembed', true ),
'#https?://(www\.)?amzn\.asia/.*#i' => array( 'https://read.amazon.com.au/kp/api/oembed', true ),
'#https?://(www\.)?z\.cn/.*#i' => array( 'https://read.amazon.cn/kp/api/oembed', true ),
'#https?://www\.someecards\.com/.+-cards/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://www\.someecards\.com/usercards/viewcard/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://some\.ly\/.+#i' => array( 'https://www.someecards.com/v2/oembed/', true ),
'#https?://(www\.)?tiktok\.com/.*/video/.*#i' => array( 'https://www.tiktok.com/oembed', true ),
'#https?://(www\.)?tiktok\.com/@.*#i' => array( 'https://www.tiktok.com/oembed', true ),
'#https?://([a-z]{2}|www)\.pinterest\.com(\.(au|mx))?/.*#i' => array( 'https://www.pinterest.com/oembed.json', true ),
@ -154,7 +150,6 @@ class WP_oEmbed {
* | Dailymotion | dai.ly | 3.6.0 |
* | Flickr | flic.kr | 3.6.0 |
* | Spotify | spotify.com | 3.6.0 |
* | Imgur | imgur.com | 3.9.0 |
* | Animoto | animoto.com | 4.0.0 |
* | Animoto | video214.com | 4.0.0 |
* | Issuu | issuu.com | 4.0.0 |
@ -183,8 +178,6 @@ class WP_oEmbed {
* | Amazon | a.co | 4.9.0 |
* | Amazon | amzn.to (eu, in, asia) | 4.9.0 |
* | Amazon | z.cn | 4.9.0 |
* | Someecards | someecards.com | 4.9.0 |
* | Someecards | some.ly | 4.9.0 |
* | Crowdsignal | survey.fm | 5.1.0 |
* | TikTok | tiktok.com | 5.4.0 |
* | Pinterest | pinterest.com | 5.9.0 |
@ -219,6 +212,9 @@ class WP_oEmbed {
* | Meetup.com | meetu.ps | 3.9.0 | 6.0.1 |
* | SlideShare | slideshare.net | 3.5.0 | 6.6.0 |
* | Screencast | screencast.com | 4.8.0 | 6.8.2 |
* | Imgur | imgur.com | 3.9.0 | 7.1.3 |
* | Someecards | someecards.com | 4.9.0 | 7.1.3 |
* | Someecards | some.ly | 4.9.0 | 7.1.3 |
*
* @see wp_oembed_add_provider()
*

View File

@ -3484,43 +3484,6 @@ class WP_Query {
$this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
}
if ( ! empty( $this->posts ) && $this->is_comment_feed && $this->is_singular ) {
/** This filter is documented in wp-includes/class-wp-query.php */
$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
/** This filter is documented in wp-includes/class-wp-query.php */
$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1' AND {$wpdb->comments}.comment_type != 'note'", &$this ) );
/** This filter is documented in wp-includes/class-wp-query.php */
$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
/** This filter is documented in wp-includes/class-wp-query.php */
$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
/** This filter is documented in wp-includes/class-wp-query.php */
$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option( 'posts_per_rss' ), &$this ) );
$comments_request = "SELECT {$wpdb->comments}.comment_ID FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
$comment_key = md5( $comments_request );
$comment_last_changed = wp_cache_get_last_changed( 'comment' );
$comment_cache_key = "comment_feed:$comment_key";
$comment_ids = wp_cache_get_salted( $comment_cache_key, 'comment-queries', $comment_last_changed );
if ( false === $comment_ids ) {
$comment_ids = $wpdb->get_col( $comments_request );
wp_cache_set_salted( $comment_cache_key, $comment_ids, 'comment-queries', $comment_last_changed );
}
_prime_comment_caches( $comment_ids );
// Convert to WP_Comment.
/** @var WP_Comment[] */
$this->comments = array_map( 'get_comment', $comment_ids );
$this->comment_count = count( $this->comments );
}
// Check post status to determine if post should be displayed.
if ( ! empty( $this->posts ) && ( $this->is_single || $this->is_page ) ) {
$status = get_post_status( $this->posts[0] );
@ -3579,6 +3542,43 @@ class WP_Query {
}
}
if ( ! empty( $this->posts ) && $this->is_comment_feed && $this->is_singular ) {
/** This filter is documented in wp-includes/class-wp-query.php */
$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
/** This filter is documented in wp-includes/class-wp-query.php */
$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1' AND {$wpdb->comments}.comment_type != 'note'", &$this ) );
/** This filter is documented in wp-includes/class-wp-query.php */
$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
/** This filter is documented in wp-includes/class-wp-query.php */
$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
/** This filter is documented in wp-includes/class-wp-query.php */
$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option( 'posts_per_rss' ), &$this ) );
$comments_request = "SELECT {$wpdb->comments}.comment_ID FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
$comment_key = md5( $comments_request );
$comment_last_changed = wp_cache_get_last_changed( 'comment' );
$comment_cache_key = "comment_feed:$comment_key";
$comment_ids = wp_cache_get_salted( $comment_cache_key, 'comment-queries', $comment_last_changed );
if ( false === $comment_ids ) {
$comment_ids = $wpdb->get_col( $comments_request );
wp_cache_set_salted( $comment_cache_key, $comment_ids, 'comment-queries', $comment_last_changed );
}
_prime_comment_caches( $comment_ids );
// Convert to WP_Comment.
/** @var WP_Comment[] */
$this->comments = array_map( 'get_comment', $comment_ids );
$this->comment_count = count( $this->comments );
}
// Put sticky posts at the top of the posts array.
$sticky_posts = get_option( 'sticky_posts' );
if ( $this->is_home && $page <= 1 && is_array( $sticky_posts ) && ! empty( $sticky_posts ) && ! $query_vars['ignore_sticky_posts'] ) {

View File

@ -3880,8 +3880,18 @@ class WP_Theme_JSON {
// Only store if the variation has blockGap defined.
if ( isset( $style_variation_node['spacing']['blockGap'] ) ) {
// Append block selector to the variation selector for proper targeting.
$variation_metadata_with_selector = $style_variation;
$variation_metadata_with_selector['selector'] = $style_variation['selector'] . $block_metadata['css'];
$variation_metadata_with_selector = $style_variation;
$variation_metadata_with_selector['selector'] = $style_variation['selector'] . $block_metadata['css'];
/*
* `get_layout_styles()` reads `name` as a block name, to check that the block
* supports layout at all. A variation node's `name` is the variation slug,
* which is never a registered block, so the check fails and every variation
* gap rule is discarded. Pass the block the variation belongs to, so the
* support check answers the question it is actually asking.
*/
$variation_metadata_with_selector['name'] = $block_name;
$style_variation_layout_metadata[ $style_variation['selector'] ] = array(
'metadata' => $variation_metadata_with_selector,
'node' => $style_variation_node,
@ -3937,7 +3947,11 @@ class WP_Theme_JSON {
if ( isset( $breakpoint_node['spacing']['blockGap'] ) ) {
$variation_layout_metadata = $style_variation;
$variation_layout_metadata['selector'] = $style_variation['selector'] . $block_metadata['css'];
$variation_responsive_css .= $this->get_layout_styles(
// The variation slug is not a block name here either. See above.
$variation_layout_metadata['name'] = $block_name;
$variation_responsive_css .= $this->get_layout_styles(
$variation_layout_metadata,
array(
'node' => $breakpoint_node,

View File

@ -16,11 +16,25 @@
#[AllowDynamicProperties]
class WP_Widget_Factory {
/**
* Prefix for the key under which a widget registered as an instance is stored.
*
* Without it the key would be the decimal representation of an integer, which PHP casts from
* string to int when it is used as an array key.
*
* @since 7.1.1
*/
private const INSTANCE_KEY_PREFIX = 'spl_object_id:';
/**
* Widgets array.
*
* Keyed by class name for a widget registered by name, and by a prefixed object ID for a widget
* registered as an instance.
*
* @since 2.8.0
* @var array
* @var array<string, WP_Widget>
* @phpstan-var array<non-decimal-int-string, WP_Widget>
*/
public $widgets = array();
@ -52,12 +66,13 @@ class WP_Widget_Factory {
* @since 2.8.0
* @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
* instead of simply a `WP_Widget` subclass name.
* @since 7.1.1 The key for an instance is prefixed so that it is never cast to an integer.
*
* @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
*/
public function register( $widget ) {
if ( $widget instanceof WP_Widget ) {
$this->widgets[ spl_object_id( $widget ) ] = $widget;
$this->widgets[ self::INSTANCE_KEY_PREFIX . spl_object_id( $widget ) ] = $widget;
} else {
$this->widgets[ $widget ] = new $widget();
}
@ -69,12 +84,13 @@ class WP_Widget_Factory {
* @since 2.8.0
* @since 4.6.0 Updated the `$widget` parameter to also accept a WP_Widget instance object
* instead of simply a `WP_Widget` subclass name.
* @since 7.1.1 The key for an instance is prefixed so that it is never cast to an integer.
*
* @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass.
*/
public function unregister( $widget ) {
if ( $widget instanceof WP_Widget ) {
unset( $this->widgets[ spl_object_id( $widget ) ] );
unset( $this->widgets[ self::INSTANCE_KEY_PREFIX . spl_object_id( $widget ) ] );
} else {
unset( $this->widgets[ $widget ] );
}

View File

@ -1462,6 +1462,33 @@ class wp_xmlrpc_server extends IXR_Server {
return new IXR_Error( 403, __( 'Invalid post type.' ) );
}
// Reject writes to internal-only builtin post types (e.g. customize_changeset)
// whose intended write path is a dedicated helper, not a generic post API.
$is_internal_only = (
empty( $post_type->public )
&& empty( $post_type->show_in_rest )
&& ! empty( $post_type->_builtin )
);
/**
* Filters whether a post type accepts writes via XML-RPC.
*
* Defaults to false for internal-only builtin post types (public=false,
* show_in_rest=false, _builtin=true), such as customize_changeset, whose
* writes are meant to flow through dedicated helpers. Return true to opt
* a post type back in.
*
* @since 7.1.1
*
* @param bool $allowed Whether the post type accepts XML-RPC writes.
* @param WP_Post_Type $post_type The post type object.
*/
$allowed = apply_filters( 'xmlrpc_allow_post_type_writes', ! $is_internal_only, $post_type );
if ( ! $allowed ) {
return new IXR_Error( 403, __( 'Sorry, this post type is not supported over XML-RPC.' ) );
}
$update = ! empty( $post_data['ID'] );
if ( $update ) {

View File

@ -746,8 +746,9 @@ class WP {
$set_404 = true;
// Never 404 for the admin, robots, or favicon.
if ( is_admin() || is_robots() || is_favicon() ) {
// Never 404 here for the admin, robots, favicon, or sitemaps.
// Sitemap routes send their own status in WP_Sitemaps::render_sitemaps().
if ( is_admin() || is_robots() || is_favicon() || is_sitemap() || get_query_var( 'sitemap-stylesheet' ) ) {
$set_404 = false;
// If posts were found, check for paged content.

View File

@ -599,10 +599,14 @@ html:lang(he-il) .rtl #wpadminbar * {
content: none;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
/* The adminbar icon needs additional styling to prevent 3rd party styles from overriding the size. */
#wpadminbar #wp-admin-bar-site-name > .ab-item img.site-icon {
width: 20px;
height: 20px;
background: #f0f0f1; /* matching my-account (user avatar) node's background */
max-width: 20px;
max-height: 20px;
min-width: 20px;
min-height: 20px;
border-radius: 2px;
}
@ -940,12 +944,24 @@ html:lang(he-il) .rtl #wpadminbar * {
-moz-osx-font-smoothing: grayscale;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
/*
* Flex prevents `text-indent` from hiding the site title, and is unused here
* since the icon is positioned absolutely below.
*/
#wpadminbar #wp-admin-bar-site-name.has-site-icon > .ab-item {
display: block;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item img.site-icon {
position: absolute;
top: 9px;
right: 12px;
width: 28px;
height: 28px;
max-width: 28px;
max-height: 28px;
min-width: 28px;
min-height: 28px;
margin: 0;
border-radius: 4px;
}

File diff suppressed because one or more lines are too long

View File

@ -598,10 +598,14 @@ html:lang(he-il) .rtl #wpadminbar * {
content: none;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
/* The adminbar icon needs additional styling to prevent 3rd party styles from overriding the size. */
#wpadminbar #wp-admin-bar-site-name > .ab-item img.site-icon {
width: 20px;
height: 20px;
background: #f0f0f1; /* matching my-account (user avatar) node's background */
max-width: 20px;
max-height: 20px;
min-width: 20px;
min-height: 20px;
border-radius: 2px;
}
@ -939,12 +943,24 @@ html:lang(he-il) .rtl #wpadminbar * {
-moz-osx-font-smoothing: grayscale;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item .site-icon {
/*
* Flex prevents `text-indent` from hiding the site title, and is unused here
* since the icon is positioned absolutely below.
*/
#wpadminbar #wp-admin-bar-site-name.has-site-icon > .ab-item {
display: block;
}
#wpadminbar #wp-admin-bar-site-name > .ab-item img.site-icon {
position: absolute;
top: 9px;
left: 12px;
width: 28px;
height: 28px;
max-width: 28px;
max-height: 28px;
min-width: 28px;
min-height: 28px;
margin: 0;
border-radius: 4px;
}

File diff suppressed because one or more lines are too long

View File

@ -59,7 +59,10 @@
}
.wp-block-accordion-panel[hidden] {
border: none !important;
box-shadow: none !important;
margin-block-start: 0;
padding: 0 !important;
}
.wp-block-archives {

File diff suppressed because one or more lines are too long

View File

@ -59,7 +59,10 @@
}
.wp-block-accordion-panel[hidden] {
border: none !important;
box-shadow: none !important;
margin-block-start: 0;
padding: 0 !important;
}
.wp-block-archives {

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,17 @@
* @since 3.4.0
*
* @see WP_Customize_Setting
*
* @phpstan-type Header_Image_Data array{
* attachment_id?: int,
* url?: string,
* thumbnail_url?: string,
* timestamp?: int,
* width?: int,
* height?: int,
* alt_text?: string,
* attachment_parent?: int,
* }
*/
final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
@ -62,4 +73,163 @@ final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
}
return true;
}
/**
* Sanitizes a header value.
*
* The value is expected to be one of the following:
*
* - An array of header image data, with the keys `attachment_id`, `url`, `thumbnail_url`, `timestamp`, `width`,
* `height`, `alt_text`, and `attachment_parent`, as supplied by {@see get_uploaded_header_images()}. Any other
* key is discarded.
* - An array with a `choice` key, being the legacy format in which any of the other accepted values is nested.
* - The string `remove-header`, `random-default-image`, or `random-uploaded-image`.
* - A string corresponding to one of the keys for the array returned by {@see get_uploaded_header_images()}, or
* one of the keys for the array passed into {@see register_default_headers()}.
*
* @since 7.1.1
*
* @see WP_Customize_Header_Image_Setting::update()
* @see Custom_Image_Header::set_header_image()
*
* @param mixed $value Value to sanitize.
* @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid. The array holds
* the header image data, or that data nested under a `choice` key,
* before the `customize_sanitize_header_image_data` filter, which
* may return anything, is applied to it.
*
* @phpstan-return array<mixed, mixed>|string|WP_Error|null
*/
public function sanitize( $value ) {
/*
* The update() method unwraps the legacy `choice` format before handing the value off to
* Custom_Image_Header::set_header_image(), so the nested value is what must be sanitized.
*/
if ( is_array( $value ) && isset( $value['choice'] ) ) {
$choice = $this->sanitize_choice( $value['choice'] );
if ( is_null( $choice ) || is_wp_error( $choice ) ) {
return $choice;
}
$value = array( 'choice' => $choice );
} else {
$value = $this->sanitize_choice( $value );
if ( is_null( $value ) || is_wp_error( $value ) ) {
return $value;
}
}
return parent::sanitize( $value );
}
/**
* Sanitizes a header image choice.
*
* This is the value which is ultimately passed to {@see Custom_Image_Header::set_header_image()}, whether
* supplied at the top level of the setting value or nested under its legacy `choice` key.
*
* @since 7.1.1
*
* @param mixed $value Value to sanitize.
* @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid.
*
* @phpstan-return Header_Image_Data|string|WP_Error|null
*/
private function sanitize_choice( $value ) {
// Custom_Image_Header::set_header_image() accepts an object in place of an array.
if ( is_object( $value ) ) {
$value = (array) $value;
}
if ( is_string( $value ) ) {
return sanitize_text_field( $value );
}
if ( ! is_array( $value ) ) {
return null;
}
/*
* The sanitized value is assembled member by member rather than filtered down from the
* supplied one, so that nothing but the members below can end up in it.
*/
$sanitized = array();
if ( isset( $value['attachment_id'] ) ) {
if ( ! is_scalar( $value['attachment_id'] ) ) {
return null;
}
$attachment_id = absint( $value['attachment_id'] );
/*
* A supplied attachment must be an existing image, since its ID is written to postmeta and its
* data displayed. Note that an ID of zero must be skipped rather than looked up, as
* get_post_mime_type() falls back to the global post when passed an empty value.
*/
if ( $attachment_id > 0 ) {
$mime_type = get_post_mime_type( $attachment_id );
if ( ! is_string( $mime_type ) || ! str_starts_with( $mime_type, 'image/' ) ) {
return null;
}
}
$sanitized['attachment_id'] = $attachment_id;
}
if ( isset( $value['url'] ) ) {
if ( ! is_string( $value['url'] ) ) {
return null;
}
$sanitized['url'] = sanitize_url( $value['url'] );
if ( '' === $sanitized['url'] ) {
return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) );
}
}
if ( isset( $value['thumbnail_url'] ) ) {
if ( ! is_string( $value['thumbnail_url'] ) ) {
return null;
}
$sanitized['thumbnail_url'] = sanitize_url( $value['thumbnail_url'] );
if ( '' === $sanitized['thumbnail_url'] ) {
return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) );
}
}
if ( isset( $value['timestamp'] ) ) {
if ( ! is_scalar( $value['timestamp'] ) ) {
return null;
}
$sanitized['timestamp'] = absint( $value['timestamp'] );
}
if ( isset( $value['width'] ) ) {
if ( ! is_scalar( $value['width'] ) ) {
return null;
}
$sanitized['width'] = absint( $value['width'] );
}
if ( isset( $value['height'] ) ) {
if ( ! is_scalar( $value['height'] ) ) {
return null;
}
$sanitized['height'] = absint( $value['height'] );
}
if ( isset( $value['alt_text'] ) ) {
if ( ! is_string( $value['alt_text'] ) ) {
return null;
}
$sanitized['alt_text'] = sanitize_text_field( $value['alt_text'] );
}
if ( isset( $value['attachment_parent'] ) ) {
if ( ! is_scalar( $value['attachment_parent'] ) ) {
return null;
}
$sanitized['attachment_parent'] = absint( $value['attachment_parent'] );
}
return $sanitized;
}
}

View File

@ -560,7 +560,7 @@ function wpautop( $text, $br = true ) {
$text = preg_replace( '|<p>(<li.+?)</p>|', '$1', $text );
// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
$text = preg_replace( '|<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $text );
$text = preg_replace( '!<p><blockquote((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>!i', '<blockquote$1><p>', $text );
$text = str_replace( '</blockquote></p>', '</p></blockquote>', $text );
// If an opening or closing block element tag is preceded by an opening <p> tag, remove it.

View File

@ -384,7 +384,7 @@ function get_search_form( $args = array() ) {
* @type string $id Unique ID for the popover element. Default is a
* generated unique ID.
* @type string $button Existing `button` or `a` markup. Used instead of generated button.
* Default standard button HTML.
* Default empty string.
* @type string $label Not used for tooltips.
* @type string $close_label Not used for tooltips.
* @type string $icon Dashicons icon class for the toggle button.
@ -414,7 +414,7 @@ function wp_get_tooltip( $content, $args = array() ) {
* @type string $id Unique ID for the popover element. Default is a
* generated unique ID.
* @type string $button Existing `button` markup. Used instead of generated button.
* Default standard button HTML.
* Default empty string.
* @type string $label Accessible label for the toggle button.
* Default 'Help', matching the default icon.
* Ignored for tooltips.
@ -449,7 +449,7 @@ function wp_get_toggletip( $content, $args = array() ) {
* @type string $id Unique ID for the popover element. Default is a
* generated unique ID.
* @type string $button Existing `button` or `a` markup. Used instead of generated button.
* Default standard button HTML.
* Default empty string.
* @type string $label Accessible label for the toggle button.
* Default 'Help', matching the default icon.
* Ignored for tooltips.
@ -473,7 +473,7 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
$defaults = array(
'id' => wp_unique_id( 'wp-tooltip-' ),
'button' => '<button type="button" aria-label="%3$s"><span class="dashicons %4$s" aria-hidden="true"></span></button>',
'button' => '',
'label' => __( 'Help' ),
'close_label' => __( 'Close' ),
'icon' => 'dashicons-editor-help',
@ -488,39 +488,67 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
$classes .= ' ' . $args['class'];
}
$icon = ( $args['icon'] ) ? trim( $args['icon'] ) : $defaults['icon'];
$id = ( $args['id'] ) ? $args['id'] : $defaults['id'];
$button = ( $args['button'] ) ? $args['button'] : $defaults['button'];
$processed = false;
$icon = ( $args['icon'] ) ? trim( $args['icon'] ) : $defaults['icon'];
$id = ( $args['id'] ) ? $args['id'] : $defaults['id'];
// Tooltips use the content as the accessible name; toggletips use the label.
$label = ( 'tooltip' === $args['type'] ) ? wp_strip_all_tags( $content, true ) : $args['label'];
/*
* The generated button is a plain skeleton. Every dynamic attribute is
* added through the tag processor below, so caller-supplied markup is
* never scanned or substituted and a percent sign in custom markup,
* such as a percent-encoded URL, is never treated as a conversion
* specification.
*/
$default_button = '<button type="button"><span></span></button>';
$is_default = ! $args['button'];
$button = ( $args['button'] ) ? $args['button'] : $default_button;
// The accepted root element is a `button`, or an `a` for tooltips.
$tag = false;
$processor = new WP_HTML_Tag_Processor( $button );
if ( true === $processor->next_tag( 'button' ) ) {
$processor->add_class( 'wp-tooltip__toggle' );
if ( 'tooltip' !== $args['type'] ) {
$processor->set_attribute( 'popovertarget', '%2$s' );
$processor->set_attribute( 'aria-haspopup', 'dialog' );
}
$button = $processor->get_updated_html();
$processed = true;
$tag = 'button';
} else {
// Reset processor.
$processor = new WP_HTML_Tag_Processor( $button );
if ( true === $processor->next_tag( 'a' ) && 'tooltip' === $args['type'] ) {
$processor->add_class( 'wp-tooltip__toggle' );
$button = $processor->get_updated_html();
$processed = true;
if ( 'tooltip' === $args['type'] && true === $processor->next_tag( 'a' ) ) {
$tag = 'a';
}
}
if ( ! $processed ) {
// Button HTML passed was not valid.
$processor = new WP_HTML_Tag_Processor( $defaults['button'] );
$processor->add_class( 'wp-tooltip__toggle' );
if ( 'tooltip' !== $args['type'] ) {
$processor->set_attribute( 'popovertarget', '%2$s' );
$processor->set_attribute( 'aria-haspopup', 'dialog' );
}
$button = $processor->get_updated_html();
if ( false === $tag ) {
// Button HTML passed was not valid. Reset to default.
$is_default = true;
$button = $default_button;
$processor = new WP_HTML_Tag_Processor( $button );
$processor->next_tag( 'button' );
$tag = 'button';
}
/*
* Attributes that apply to every accepted button are added in one pass.
* Attributes that name the control are only added when the caller's
* markup did not already provide them.
*/
if ( null === $processor->get_attribute( 'aria-label' ) ) {
$processor->set_attribute( 'aria-label', $label );
}
$processor->add_class( 'wp-tooltip__toggle' );
if ( 'button' === $tag && 'tooltip' !== $args['type'] ) {
$processor->set_attribute( 'popovertarget', $id );
$processor->set_attribute( 'aria-haspopup', 'dialog' );
}
// The generated button also carries the dashicon on its inner span.
if ( $is_default && true === $processor->next_tag( 'span' ) ) {
$processor->set_attribute( 'class', 'dashicons ' . $icon );
$processor->set_attribute( 'aria-hidden', 'true' );
}
$button = $processor->get_updated_html();
/*
* The markup only uses phrasing content so it is valid when nested
* in a phrasing context. Sectioning content (e.g. `div`, `dialog`) will
@ -528,11 +556,9 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
* the layout. See #65660.
*/
if ( 'tooltip' === $args['type'] ) {
// Tooltips are only used to visually display labels.
$label = wp_strip_all_tags( $content, true );
$markup = sprintf(
'<span class="%1$s">
' . $button . '
%6$s
<span popover="hint" id="%2$s" class="wp-tooltip__bubble" role="tooltip">' .
'<span id="%2$s-text" class="wp-tooltip__text">%5$s</span>' .
'</span>' .
@ -542,6 +568,7 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
esc_attr( $label ),
esc_attr( $icon ),
esc_html( $content ),
$button,
);
} else {
/*
@ -551,7 +578,7 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
*/
$markup = sprintf(
'<span class="%1$s">
' . $button . '
%7$s
<span popover="auto" id="%2$s" class="wp-tooltip__bubble" role="dialog" aria-label="%3$s" tabindex="-1" autofocus>' .
'<span id="%2$s-text" class="wp-tooltip__text">%5$s</span>' .
'<button type="button" class="wp-tooltip__close" popovertarget="%2$s" popovertargetaction="hide" aria-label="%6$s">' .
@ -561,10 +588,11 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
'</span>',
esc_attr( $classes ),
esc_attr( $id ),
esc_attr( $args['label'] ),
esc_attr( $label ),
esc_attr( $icon ),
esc_html( $content ),
esc_attr( $args['close_label'] ),
$button,
);
}

View File

@ -3988,7 +3988,7 @@ class WP_HTML_Tag_Processor {
self::COMMENT_AS_HTML_COMMENT === $this->comment_type
) {
// Check if the text could close the comment.
if ( 1 === preg_match( '/--!?>/', $plaintext_content ) ) {
if ( 1 === preg_match( '/^-?>|--!?>/', $plaintext_content ) ) {
_doing_it_wrong(
__METHOD__,
__( 'Comment text cannot contain a comment closer.' ),

View File

@ -920,12 +920,13 @@ final class WP_Interactivity_API {
*
* @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
* @param string $prefix The directive prefix to filter by.
* @return array An array of entries containing the directive namespace, value, suffix, and unique ID.
* @return array An array of entries containing the directive namespace, value, suffix, unique ID, and attribute name.
* @phpstan-return list<array{
* namespace: string|null,
* value: mixed,
* suffix: string|null,
* unique_id: string|null,
* attribute_name: non-empty-string,
* }>
*/
private function get_directive_entries( WP_Interactivity_API_Directives_Processor $p, string $prefix ): array {
@ -962,10 +963,11 @@ final class WP_Interactivity_API {
list( $namespace, $value ) = $this->extract_directive_value( $attribute_value, $default_namespace );
$entries[] = array(
'namespace' => $namespace,
'value' => $value,
'suffix' => $suffix,
'unique_id' => $unique_id,
'namespace' => $namespace,
'value' => $value,
'suffix' => $suffix,
'unique_id' => $unique_id,
'attribute_name' => $attribute_name,
);
}
// Sort directive entries to ensure stable ordering with the client.
@ -1113,6 +1115,24 @@ final class WP_Interactivity_API {
continue;
}
/*
* Remove a binding that would change an `object` attribute whose value KSES checks,
* so that a client runtime without this check does not apply it either.
*/
if ( 'OBJECT' === $p->get_tag() && ! self::is_bindable_object_attribute( $entry['suffix'] ) ) {
$p->remove_attribute( $entry['attribute_name'] );
_doing_it_wrong(
__METHOD__,
sprintf(
/* translators: %s: The attribute name. */
__( 'The "%s" attribute cannot be bound on an "object" element, so the binding was ignored.' ),
esc_html( $entry['suffix'] )
),
'7.1.4'
);
continue;
}
// Skip if the suffix is an event handler.
if ( str_starts_with( $entry['suffix'], 'on' ) ) {
_doing_it_wrong(
@ -1240,6 +1260,7 @@ final class WP_Interactivity_API {
) {
$result = $result ? 'true' : 'false';
}
$p->set_attribute( $entry['suffix'], $result );
} else {
$p->remove_attribute( $entry['suffix'] );
@ -1248,6 +1269,33 @@ final class WP_Interactivity_API {
}
}
/**
* Determines whether a binding may set or remove an attribute of an `object` element.
*
* KSES only allows an `object` element in post content after checking the values of its
* `data` and `type` attributes. Neither the server nor the client can repeat that check for
* a bound value, so a binding on an `object` element may only change attributes that cannot
* change what it loads: `aria-*` attributes, `data-*` attributes other than directives,
* `width`, `height`, and the global attributes KSES allows on any element. Any `aria-*`
* attribute is allowed, where KSES lists only some. A `data-wp-*` attribute is refused
* because it is a directive, which could bind `data` or `type` once rendered. The client
* runtime enforces the same set.
*
* @since 7.1.4
*
* @param string $attribute_name The name of the bound attribute.
* @return bool Whether the attribute may be bound on an `object` element.
*/
private static function is_bindable_object_attribute( string $attribute_name ): bool {
$attribute_name = strtolower( $attribute_name );
return (
str_starts_with( $attribute_name, 'aria-' ) ||
( str_starts_with( $attribute_name, 'data-' ) && ! str_starts_with( $attribute_name, 'data-wp-' ) ) ||
in_array( $attribute_name, array( 'class', 'dir', 'height', 'hidden', 'id', 'lang', 'role', 'style', 'tabindex', 'title', 'width' ), true )
);
}
/**
* Processes the `data-wp-class` directive.
*

View File

@ -415,7 +415,7 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function(
* @return {wp.customize.selectiveRefresh.Partial} The widget instance partial.
*/
ensureWidgetPlacementContainers: function( widgetId ) {
var sidebarPartial = this, widgetPartial, wasInserted = false, partialId = 'widget[' + widgetId + ']';
var sidebarPartial = this, sidebarArgs, widgetPartial, wasInserted = false, partialId = 'widget[' + widgetId + ']';
widgetPartial = api.selectiveRefresh.partial( partialId );
if ( ! widgetPartial ) {
widgetPartial = new self.WidgetPartial( partialId, {
@ -423,10 +423,17 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function(
} );
}
// Build containers from the registered sidebar, since partial params can be declared in post content.
sidebarArgs = _.findWhere( self.registeredSidebars, { id: sidebarPartial.sidebarId } );
// Make sure that there is a container element for the widget in the sidebar, if at least a placeholder.
_.each( sidebarPartial.placements(), function( sidebarPlacement ) {
var foundWidgetPlacement, widgetContainerElement;
if ( ! sidebarArgs ) {
return;
}
foundWidgetPlacement = _.find( widgetPartial.placements(), function( widgetPlacement ) {
return ( widgetPlacement.context.sidebar_instance_number === sidebarPlacement.context.instanceNumber );
} );
@ -435,8 +442,8 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function(
}
widgetContainerElement = $(
sidebarPartial.params.sidebarArgs.before_widget.replace( /%1\$s/g, widgetId ).replace( /%2\$s/g, 'widget' ) +
sidebarPartial.params.sidebarArgs.after_widget
sidebarArgs.before_widget.replace( /%1\$s/g, widgetId ).replace( /%2\$s/g, 'widget' ) +
sidebarArgs.after_widget
);
// Handle rare case where before_widget and after_widget are empty.

File diff suppressed because one or more lines are too long

View File

@ -262,9 +262,9 @@ wp.customize.selectiveRefresh = ( function( $, api ) {
if ( selector ) {
selector += ', ';
}
selector += '[data-customize-partial-id="' + partial.id + '"]'; // @todo Consider injecting customize-partial-id-${id} classnames instead.
selector += '[data-customize-partial-id="' + CSS.escape( partial.id ) + '"]';
return $( selector ).map( function() {
return $( document ).find( selector ).map( function() {
var container = $( this ), context;
context = container.data( 'customize-partial-placement-context' );

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -29319,6 +29319,13 @@ ${url}
function defaultColumnsNumber(imageCount) {
return imageCount ? Math.min(3, imageCount) : 3;
}
function isObject(value) {
return !!value && typeof value === "object" && !Array.isArray(value);
}
function isGalleryFlexLayout(layout) {
const layoutType = isObject(layout) ? layout.type : void 0;
return typeof layoutType !== "string" || layoutType === "" || layoutType === "flex";
}
var pickRelevantMediaFiles = (image, sizeSlug = "large") => {
const imageProps = Object.fromEntries(
Object.entries(image ?? {}).filter(
@ -30529,9 +30536,10 @@ ${url}
)
] });
}
function GalleryImagesPreview({ imageBlocks }) {
function GalleryImagesPreview({ imageBlocks, layout }) {
const { children, ref, className } = (0, import_block_editor97.__experimentalUseBlockPreview)({
blocks: imageBlocks
blocks: imageBlocks,
layout
});
return /* @__PURE__ */ (0, import_jsx_runtime274.jsx)(
"div",
@ -30563,6 +30571,10 @@ ${url}
} = dynamic;
const blockEditingMode = (0, import_block_editor97.useBlockEditingMode)();
const [isConfirmingDetach, setIsConfirmingDetach] = (0, import_element44.useState)(false);
const previewLayout = (0, import_element44.useMemo)(
() => isGalleryFlexLayout(attributes.layout) ? { ...attributes.layout, type: "flex" } : attributes.layout,
[attributes.layout]
);
const emptyInstructions = isResolvingDynamic ? (0, import_i18n79.__)("Loading images\u2026") : sourceDescriptor?.emptyMessage ?? (0, import_i18n79.__)("Dynamic images will appear here.");
return /* @__PURE__ */ (0, import_jsx_runtime274.jsxs)(import_jsx_runtime274.Fragment, { children: [
blockEditingMode === "default" && /* @__PURE__ */ (0, import_jsx_runtime274.jsxs)(import_jsx_runtime274.Fragment, { children: [
@ -30589,7 +30601,8 @@ ${url}
dynamicImageBlocks.length ? /* @__PURE__ */ (0, import_jsx_runtime274.jsx)(import_block_editor97.BlockContextProvider, { value: galleryContext, children: /* @__PURE__ */ (0, import_jsx_runtime274.jsx)(
GalleryImagesPreview,
{
imageBlocks: dynamicImageBlocks
imageBlocks: dynamicImageBlocks,
layout: previewLayout
}
) }) : /* @__PURE__ */ (0, import_jsx_runtime274.jsx)(
import_components45.Placeholder,
@ -36185,6 +36198,42 @@ ${text}
}
return syncedAttributes;
}
function getNewAttachmentSizeAttributes(sizeSlug, attachment) {
const sizes = attachment.media_details?.sizes;
if (!sizeSlug || sizeSlug === DEFAULT_MEDIA_SIZE_SLUG3 || !sizes) {
return void 0;
}
const sizeUrl = sizes[sizeSlug]?.source_url;
if (sizeUrl) {
return { url: sizeUrl };
}
const fullUrl = attachment.source_url ?? sizes.full?.source_url;
return fullUrl ? { url: fullUrl, sizeSlug: DEFAULT_MEDIA_SIZE_SLUG3 } : void 0;
}
function getNewAttachmentLinkAttributes(linkDestination, attachment) {
if (linkDestination === LINK_DESTINATION_MEDIA2) {
return attachment.source_url ? { href: attachment.source_url } : void 0;
}
if (linkDestination === LINK_DESTINATION_ATTACHMENT2) {
return attachment.link ? { href: attachment.link } : void 0;
}
return void 0;
}
function getNewAttachmentImageBlockAttributes(blockAttributes8, attachment) {
if (!attachment) {
return void 0;
}
return {
...getNewAttachmentSizeAttributes(
blockAttributes8.sizeSlug,
attachment
),
...getNewAttachmentLinkAttributes(
blockAttributes8.linkDestination,
attachment
)
};
}
var { openMediaEditorModalKey: openMediaEditorModalKey2 } = unlock(import_block_editor115.privateApis);
function getAttachmentFallbackForEmptyBlockMetadata({ alt, caption }) {
const attachment = {};
@ -36210,7 +36259,7 @@ ${text}
onClose,
onUrlChange
}) {
const { id, url, alt, caption } = attributes;
const { id, url, alt, caption, sizeSlug, linkDestination } = attributes;
const registry = (0, import_data50.useRegistry)();
const openMediaEditorModal = (0, import_data50.useSelect)(
(select10) => select10(import_block_editor115.store).getSettings()[openMediaEditorModalKey2],
@ -36220,7 +36269,9 @@ ${text}
id,
url,
alt,
caption: caption?.toString()
caption: caption?.toString(),
sizeSlug,
linkDestination
});
const mediaEditorMetadataBaselineRef = (0, import_element56.useRef)();
const mediaEditorMetadataSyncRequestRef = (0, import_element56.useRef)(0);
@ -36229,9 +36280,11 @@ ${text}
id,
url,
alt,
caption: caption?.toString()
caption: caption?.toString(),
sizeSlug,
linkDestination
};
}, [alt, caption, id, url]);
}, [alt, caption, id, linkDestination, sizeSlug, url]);
const getCachedAttachmentRecord = (0, import_element56.useCallback)(
(attachmentId) => registry.select(import_core_data25.store).getEditedEntityRecord(
"postType",
@ -36277,7 +36330,8 @@ ${text}
const syncRequest = ++mediaEditorMetadataSyncRequestRef.current;
const nextAttributes = {};
const currentBlockAttributes = blockAttributesRef.current;
if (newId !== currentBlockAttributes.id) {
const isNewAttachment = newId !== currentBlockAttributes.id;
if (isNewAttachment) {
nextAttributes.id = newId;
nextAttributes.url = newUrl ?? currentBlockAttributes.url;
if (nextAttributes.url !== currentBlockAttributes.url) {
@ -36289,19 +36343,37 @@ ${text}
url: nextAttributes.url
};
}
if (originalAttachment) {
if (originalAttachment || isNewAttachment) {
const resolvedAttachment = await resolveFreshAttachmentRecord(newId);
if (syncRequest !== mediaEditorMetadataSyncRequestRef.current) {
return;
}
const attachmentRecord = resolvedAttachment ?? getCachedAttachmentRecord(newId);
const latestBlockAttributes = blockAttributesRef.current;
const resolvedMetadataAttributes = getSyncedImageBlockAttributes(
latestBlockAttributes,
originalAttachment,
resolvedAttachment
);
if (Object.keys(resolvedMetadataAttributes).length) {
Object.assign(nextAttributes, resolvedMetadataAttributes);
if (originalAttachment) {
const resolvedMetadataAttributes = getSyncedImageBlockAttributes(
latestBlockAttributes,
originalAttachment,
attachmentRecord
);
if (Object.keys(resolvedMetadataAttributes).length) {
Object.assign(
nextAttributes,
resolvedMetadataAttributes
);
}
}
if (isNewAttachment) {
const derivedAttributes = getNewAttachmentImageBlockAttributes(
latestBlockAttributes,
attachmentRecord
);
if (derivedAttributes) {
Object.assign(nextAttributes, derivedAttributes);
if (derivedAttributes.url && derivedAttributes.url !== latestBlockAttributes.url) {
onUrlChange?.(derivedAttributes.url);
}
}
}
}
if (Object.keys(nextAttributes).length) {
@ -36312,7 +36384,12 @@ ${text}
setAttributes(nextAttributes);
}
},
[onUrlChange, resolveFreshAttachmentRecord, setAttributes]
[
getCachedAttachmentRecord,
onUrlChange,
resolveFreshAttachmentRecord,
setAttributes
]
);
const openImageMediaEditorModal = (0, import_element56.useCallback)(async () => {
if (!id || !openMediaEditorModal) {
@ -36563,7 +36640,8 @@ ${text}
setOffsetTop(imageElement?.offsetTop ?? 0);
}, [imageElement]);
const setRefs = (0, import_compose24.useMergeRefs)([setImageElement, setResizeObserved]);
const { allowResize = true } = context;
const { allowResize = true, imageCrop = false } = context;
const isCroppedGalleryImage = imageCrop && parentLayoutType === "flex";
const { image, attachmentResolutionError } = (0, import_data51.useSelect)(
(select10) => {
const imageRecord = id && isSingleSelected ? select10(import_core_data26.store).getEntityRecord(
@ -37287,10 +37365,12 @@ ${text}
} else if (width !== void 0 && width !== null) {
style2.width = typeof width === "number" ? `${width}px` : width;
}
if (height === "auto" || height === void 0 || height === null) {
if (height === "auto") {
style2.height = "auto";
} else {
} else if (height !== void 0 && height !== null) {
style2.height = typeof height === "number" ? `${height}px` : height;
} else if (!isCroppedGalleryImage) {
style2.height = "auto";
}
return style2;
})(),
@ -40887,20 +40967,14 @@ ${text}
var import_blocks45 = __toESM(require_blocks(), 1);
function useOutdentListItem() {
const registry = (0, import_data57.useRegistry)();
const {
moveBlocksToPosition,
removeBlock,
insertBlock,
updateBlockListSettings
} = (0, import_data57.useDispatch)(import_block_editor128.store);
const { moveBlocksToPosition, removeBlock, removeBlocks, insertBlock } = (0, import_data57.useDispatch)(import_block_editor128.store);
const {
getBlockRootClientId,
getBlockName,
getBlockOrder,
getBlockIndex,
getSelectedBlockClientIds,
getBlock,
getBlockListSettings
getBlock
} = (0, import_data57.useSelect)(import_block_editor128.store);
function getParentListItemId(id) {
const listId = getBlockRootClientId(id);
@ -40936,25 +41010,22 @@ ${text}
);
registry.batch(() => {
if (followingListItems.length) {
let nestedListId = getBlockOrder(firstClientId)[0];
if (!nestedListId) {
const nestedListId = getBlockOrder(firstClientId)[0];
if (nestedListId) {
moveBlocksToPosition(
followingListItems,
parentListId,
nestedListId
);
} else {
const nestedListBlock = (0, import_blocks45.cloneBlock)(
getBlock(parentListId),
{},
[]
followingListItems.map((id) => getBlock(id))
);
nestedListId = nestedListBlock.clientId;
removeBlocks(followingListItems, false);
insertBlock(nestedListBlock, 0, firstClientId, false);
updateBlockListSettings(
nestedListId,
getBlockListSettings(parentListId)
);
}
moveBlocksToPosition(
followingListItems,
parentListId,
nestedListId
);
}
moveBlocksToPosition(
clientIds,
@ -60530,7 +60601,9 @@ ${text}
query: {
perPage,
offset = 0,
postType,
// Match `build_query_vars_from_query_block()`, which queries posts when
// `query` has no post type.
postType = "post",
order,
orderBy,
author,
@ -64047,7 +64120,9 @@ ${text}
orderBy,
author: authorIds,
pages,
postType,
// Match `build_query_vars_from_query_block()`, which queries posts when
// `query` has no post type.
postType = "post",
perPage,
offset,
sticky,
@ -64135,7 +64210,7 @@ ${text}
);
const showExcludeCurrentControl = shouldExcludeCurrentPost && isControlAllowed(allowedControls, "excludeCurrent");
const postTypeSingularName = (0, import_data125.useSelect)(
(select10) => select10(import_core_data77.store).getPostType(postType)?.labels.singular_name,
(select10) => select10(import_core_data77.store).getPostType(postType)?.labels?.singular_name,
[postType]
);
const showFiltersPanel = showTaxControl || showAuthorControl || showSearchControl || showParentControl || showFormatControl || showExcludeCurrentControl;
@ -68050,7 +68125,7 @@ ${text}
}
// packages/block-library/build-module/block/deprecated.mjs
var isObject = (obj) => typeof obj === "object" && !Array.isArray(obj) && obj !== null;
var isObject2 = (obj) => typeof obj === "object" && !Array.isArray(obj) && obj !== null;
var v219 = {
attributes: {
ref: {
@ -68073,7 +68148,7 @@ ${text}
// the likelihood, it doesn't solve it completely.
isEligible({ content }) {
return !!content && Object.keys(content).every(
(contentKey) => content[contentKey].values && isObject(content[contentKey].values)
(contentKey) => content[contentKey].values && isObject2(content[contentKey].values)
);
},
/*

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@ var wp;
var offset;
var output;
var stack;
var tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
var tokenizer = /<!--[ \t\f\r\n]+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)[ \t\f\r\n]+({(?:(?=([^}]+|}+(?=})|(?!}[ \t\f\r\n]+\/?-->)[^])*)\5|[^]*?)}[ \t\f\r\n]+)?(\/)?-->/g;
function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
return {
blockName,

View File

@ -1,5 +1,5 @@
/*! This file is auto-generated */
(function() {
"use strict";var wp;(wp||={}).blockSerializationDefaultParser=(()=>{var m=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var F=(t,e)=>{for(var s in e)m(t,s,{get:e[s],enumerable:!0})},H=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of T(e))!B.call(t,n)&&n!==s&&m(t,n,{get:()=>e[n],enumerable:!(o=S(e,n))||o.enumerable});return t};var w=t=>H(m({},"__esModule",{value:!0}),t);var L={};F(L,{parse:()=>y});var a,l,i,f,C=/<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;function k(t,e,s,o,n){return{blockName:t,attrs:e,innerBlocks:s,innerHTML:o,innerContent:n}}function g(t){return k(null,{},[],t,[t])}function N(t,e,s,o,n){return{block:t,tokenStart:e,tokenLength:s,prevOffset:o||e+s,leadingHtmlStart:n}}var y=t=>{a=t,l=0,i=[],f=[],C.lastIndex=0;do;while(A());return i};function A(){let t=f.length,e=J(),[s,o,n,r,c]=e,p=r>l?l:null;switch(s){case"no-more-tokens":if(t===0)return d(),!1;if(t===1)return v(),!1;for(;0<f.length;)v();return!1;case"void-block":return t===0?(p!==null&&i.push(g(a.substr(p,r-p))),i.push(k(o,n,[],"",[])),l=r+c,!0):(z(k(o,n,[],"",[]),r,c),l=r+c,!0);case"block-opener":return f.push(N(k(o,n,[],"",[]),r,c,r+c,p)),l=r+c,!0;case"block-closer":if(t===0)return d(),!1;if(t===1)return v(r),l=r+c,!0;let u=f.pop(),h=a.substr(u.prevOffset,r-u.prevOffset);return u.block.innerHTML+=h,u.block.innerContent.push(h),u.prevOffset=r+c,z(u.block,u.tokenStart,u.tokenLength,r+c),l=r+c,!0;default:return d(),!1}}function I(t){try{return JSON.parse(t)}catch{return null}}function J(){let t=C.exec(a);if(t===null)return["no-more-tokens","",null,0,0];let e=t.index,[s,o,n,r,c,,p]=t,u=s.length,h=!!o,O=!!p,b=(n||"core/")+r,M=!!c,x=M?I(c):{};return O?["void-block",b,x,e,u]:h?["block-closer",b,null,e,u]:["block-opener",b,x,e,u]}function d(t){let e=t||a.length-l;e!==0&&i.push(g(a.substr(l,e)))}function z(t,e,s,o){let n=f[f.length-1];n.block.innerBlocks.push(t);let r=a.substr(n.prevOffset,e-n.prevOffset);r&&(n.block.innerHTML+=r,n.block.innerContent.push(r)),n.block.innerContent.push(null),n.prevOffset=o||e+s}function v(t){let{block:e,leadingHtmlStart:s,prevOffset:o,tokenStart:n}=f.pop(),r=t?a.substr(o,t-o):a.substr(o);r&&(e.innerHTML+=r,e.innerContent.push(r)),s!==null&&i.push(g(a.substr(s,n-s))),i.push(e)}return w(L);})();
"use strict";var wp;(wp||={}).blockSerializationDefaultParser=(()=>{var m=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var F=(t,n)=>{for(var s in n)m(t,s,{get:n[s],enumerable:!0})},H=(t,n,s,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of T(n))!B.call(t,e)&&e!==s&&m(t,e,{get:()=>n[e],enumerable:!(o=S(n,e))||o.enumerable});return t};var w=t=>H(m({},"__esModule",{value:!0}),t);var L={};F(L,{parse:()=>y});var a,l,i,f,C=/<!--[ \t\f\r\n]+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)[ \t\f\r\n]+({(?:(?=([^}]+|}+(?=})|(?!}[ \t\f\r\n]+\/?-->)[^])*)\5|[^]*?)}[ \t\f\r\n]+)?(\/)?-->/g;function k(t,n,s,o,e){return{blockName:t,attrs:n,innerBlocks:s,innerHTML:o,innerContent:e}}function g(t){return k(null,{},[],t,[t])}function N(t,n,s,o,e){return{block:t,tokenStart:n,tokenLength:s,prevOffset:o||n+s,leadingHtmlStart:e}}var y=t=>{a=t,l=0,i=[],f=[],C.lastIndex=0;do;while(A());return i};function A(){let t=f.length,n=J(),[s,o,e,r,c]=n,p=r>l?l:null;switch(s){case"no-more-tokens":if(t===0)return d(),!1;if(t===1)return v(),!1;for(;0<f.length;)v();return!1;case"void-block":return t===0?(p!==null&&i.push(g(a.substr(p,r-p))),i.push(k(o,e,[],"",[])),l=r+c,!0):(z(k(o,e,[],"",[]),r,c),l=r+c,!0);case"block-opener":return f.push(N(k(o,e,[],"",[]),r,c,r+c,p)),l=r+c,!0;case"block-closer":if(t===0)return d(),!1;if(t===1)return v(r),l=r+c,!0;let u=f.pop(),h=a.substr(u.prevOffset,r-u.prevOffset);return u.block.innerHTML+=h,u.block.innerContent.push(h),u.prevOffset=r+c,z(u.block,u.tokenStart,u.tokenLength,r+c),l=r+c,!0;default:return d(),!1}}function I(t){try{return JSON.parse(t)}catch{return null}}function J(){let t=C.exec(a);if(t===null)return["no-more-tokens","",null,0,0];let n=t.index,[s,o,e,r,c,,p]=t,u=s.length,h=!!o,O=!!p,b=(e||"core/")+r,M=!!c,x=M?I(c):{};return O?["void-block",b,x,n,u]:h?["block-closer",b,null,n,u]:["block-opener",b,x,n,u]}function d(t){let n=t||a.length-l;n!==0&&i.push(g(a.substr(l,n)))}function z(t,n,s,o){let e=f[f.length-1];e.block.innerBlocks.push(t);let r=a.substr(e.prevOffset,n-e.prevOffset);r&&(e.block.innerHTML+=r,e.block.innerContent.push(r)),e.block.innerContent.push(null),e.prevOffset=o||n+s}function v(t){let{block:n,leadingHtmlStart:s,prevOffset:o,tokenStart:e}=f.pop(),r=t?a.substr(o,t-o):a.substr(o);r&&(n.innerHTML+=r,n.innerContent.push(r)),s!==null&&i.push(g(a.substr(s,e-s))),i.push(n)}return w(L);})();
(window.wp ||= {}).blockSerializationDefaultParser = wp.blockSerializationDefaultParser;
})();

View File

@ -140,7 +140,7 @@ var wp;
return "core/" + type;
}, peg$c21 = /^[a-z]/, peg$c22 = peg$classExpectation([["a", "z"]], false, false), peg$c23 = /^[a-z0-9_\-]/, peg$c24 = peg$classExpectation([["a", "z"], ["0", "9"], "_", "-"], false, false), peg$c25 = peg$otherExpectation("JSON-encoded attributes embedded in a block's opening comment"), peg$c26 = "{", peg$c27 = peg$literalExpectation("{", false), peg$c28 = "}", peg$c29 = peg$literalExpectation("}", false), peg$c30 = "", peg$c31 = function(attrs) {
return maybeJSON(attrs);
}, peg$c32 = /^[ \t\r\n]/, peg$c33 = peg$classExpectation([" ", " ", "\r", "\n"], false, false), peg$currPos = 0, peg$savedPos = 0, peg$posDetailsCache = [{ line: 1, column: 1 }], peg$maxFailPos = 0, peg$maxFailExpected = [], peg$silentFails = 0, peg$result;
}, peg$c32 = /^[ \t\f\r\n]/, peg$c33 = peg$classExpectation([" ", " ", "\f", "\r", "\n"], false, false), peg$currPos = 0, peg$savedPos = 0, peg$posDetailsCache = [{ line: 1, column: 1 }], peg$maxFailPos = 0, peg$maxFailExpected = [], peg$silentFails = 0, peg$result;
if ("startRule" in options) {
if (!(options.startRule in peg$startRuleFunctions)) {
throw new Error(`Can't start parsing from rule "` + options.startRule + '".');

File diff suppressed because one or more lines are too long

View File

@ -11932,7 +11932,6 @@ var wp;
core.__experimentalGetCurrentThemeBaseGlobalStyles(),
core.__experimentalGetCurrentThemeGlobalStylesVariations(),
core.getEntityRecord("root", "__unstableBase"),
core.getEntityRecord("root", "site"),
core.canUser("read", { kind: "root", name: "site" }),
core.canUser("create", { kind: "postType", name: "attachment" }),
core.canUser("create", { kind: "postType", name: "page" }),
@ -11970,11 +11969,13 @@ var wp;
] : []
]);
const tasks = [];
if (coreSelect.canUser("read", { kind: "root", name: "site" })) {
tasks.push(core.getEntityRecord("root", "site"));
}
const globalStylesId = coreSelect.__experimentalGetCurrentGlobalStylesId();
if (globalStylesId) {
tasks.push(
core.getEntityRecord("root", "globalStyles", globalStylesId),
core.canUser("read", {
core.canUser("update", {
kind: "root",
name: "globalStyles",
id: globalStylesId
@ -12006,6 +12007,26 @@ var wp;
if (tasks.length) {
await Promise.all(tasks);
}
if (globalStylesId) {
if (coreSelect.canUser("update", {
kind: "root",
name: "globalStyles",
id: globalStylesId
})) {
await core.getEntityRecord(
"root",
"globalStyles",
globalStylesId
);
} else {
await core.getEntityRecord(
"root",
"globalStyles",
globalStylesId,
{ context: "view" }
);
}
}
} catch {
}
}

File diff suppressed because one or more lines are too long

View File

@ -54928,9 +54928,13 @@ If there's a particular need for this, please submit a feature request at https:
const fieldsKey = fieldList ? [...fieldList].sort().join(",") : void 0;
return (0, import_data65.useSelect)(
(select4) => {
return unlock7(select4(import_core_data41.store)).getViewConfig(kind, name2, {
fields: fieldsKey
});
return unlock7(select4(import_core_data41.store)).getViewConfig(
kind,
name2,
fieldsKey ? {
fields: fieldsKey
} : void 0
);
},
[kind, name2, fieldsKey]
);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1334,7 +1334,7 @@ var wp;
return data !== null && typeof data === "object" && Object.getPrototypeOf(data) === Object.prototype;
}
function flattenFormData(formData, key, data) {
if (isPlainObject(data)) {
if (Array.isArray(data) || isPlainObject(data)) {
for (const [name, value] of Object.entries(data)) {
flattenFormData(formData, `${key}[${name}]`, value);
}
@ -1361,11 +1361,7 @@ var wp;
const data = new FormData();
data.append("file", file, file.name || file.type.replace("/", "."));
for (const [key, value] of Object.entries(additionalData)) {
flattenFormData(
data,
key,
value
);
flattenFormData(data, key, value);
}
return transformAttachment(
await (0, import_api_fetch.default)({
@ -1587,11 +1583,7 @@ var wp;
const data = new FormData();
data.append("file", file, file.name || file.type.replace("/", "."));
for (const [key, value] of Object.entries(additionalData)) {
flattenFormData(
data,
key,
value
);
flattenFormData(data, key, value);
}
return (0, import_api_fetch2.default)({
path: `/wp/v2/media/${attachmentId}/sideload`,

File diff suppressed because one or more lines are too long

View File

@ -29,6 +29,10 @@ function getImageSrc({ uploadedSrc }) {
function getImageSrcset({ lightboxSrcset }) {
return lightboxSrcset || "";
}
function getImageMetadata(imageId) {
const metadata = state.metadata[imageId];
return Object.hasOwn(state.metadata, imageId) ? metadata : void 0;
}
var { state, actions, callbacks } = store(
"core/image",
{
@ -55,7 +59,7 @@ var { state, actions, callbacks } = store(
);
},
get selectedImage() {
return state.metadata[state.selectedImageId];
return getImageMetadata(state.selectedImageId);
},
get hasNavigationIcon() {
const { navigationButtonType } = state.selectedImage;
@ -67,7 +71,7 @@ var { state, actions, callbacks } = store(
},
get thisImage() {
const { imageId } = getContext();
return state.metadata[imageId];
return getImageMetadata(imageId);
},
get hasNavigation() {
return state.galleryImages.length > 1;
@ -129,7 +133,7 @@ var { state, actions, callbacks } = store(
actions: {
showLightbox() {
const { imageId } = getContext();
if (!state.metadata[imageId].imageRef?.complete) {
if (!getImageMetadata(imageId)?.imageRef?.complete) {
return;
}
state.scrollTopReset = document.documentElement.scrollTop;
@ -244,7 +248,10 @@ var { state, actions, callbacks } = store(
if (state.preloadedImageIds.has(imageId)) {
return;
}
const imageMetadata = state.metadata[imageId];
const imageMetadata = getImageMetadata(imageId);
if (!imageMetadata) {
return;
}
const imageLink = document.createElement("link");
imageLink.rel = "preload";
imageLink.as = "image";
@ -393,8 +400,12 @@ var { state, actions, callbacks } = store(
return;
}
const { imageId } = getContext();
state.metadata[imageId].imageRef = ref;
state.metadata[imageId].currentSrc = ref.currentSrc;
const imageMetadata = getImageMetadata(imageId);
if (!imageMetadata) {
return;
}
imageMetadata.imageRef = ref;
imageMetadata.currentSrc = ref.currentSrc;
const {
naturalWidth,
naturalHeight,
@ -420,7 +431,7 @@ var { state, actions, callbacks } = store(
const buttonOffsetRight = figureWidth - offsetWidth;
let buttonTop = buttonOffsetTop + 16;
let buttonRight = buttonOffsetRight + 16;
if (state.metadata[imageId].scaleAttr === "contain") {
if (imageMetadata.scaleAttr === "contain") {
const naturalRatio = naturalWidth / naturalHeight;
const offsetRatio = offsetWidth / offsetHeight;
if (naturalRatio >= offsetRatio) {
@ -433,8 +444,8 @@ var { state, actions, callbacks } = store(
buttonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16;
}
}
state.metadata[imageId].buttonTop = buttonTop;
state.metadata[imageId].buttonRight = buttonRight;
imageMetadata.buttonTop = buttonTop;
imageMetadata.buttonRight = buttonRight;
},
setOverlayFocus() {
if (state.overlayEnabled) {
@ -454,7 +465,10 @@ var { state, actions, callbacks } = store(
initTriggerButton() {
const { imageId } = getContext();
const { ref } = getElement();
state.metadata[imageId].buttonRef = ref;
const imageMetadata = getImageMetadata(imageId);
if (imageMetadata) {
imageMetadata.buttonRef = ref;
}
}
}
},

View File

@ -1 +1 @@
<?php return array('dependencies' => array(), 'module_dependencies' => array(array('id' => '@wordpress/interactivity', 'import' => 'static')), 'version' => '25ee935fd6c67371d0f3');
<?php return array('dependencies' => array(), 'module_dependencies' => array(array('id' => '@wordpress/interactivity', 'import' => 'static')), 'version' => '25f29e3c6cc00370914b');

File diff suppressed because one or more lines are too long

View File

@ -714,11 +714,32 @@ var cloneRouterRegionContent = (vdom) => {
var regionsToAttachByParent = /* @__PURE__ */ new WeakMap();
var rootFragmentsByParent = /* @__PURE__ */ new WeakMap();
var initialRegionsToAttach = /* @__PURE__ */ new Set();
var isValidPageResponse = (response) => {
if (response.status !== 200) {
return false;
}
try {
if (new URL(response.url).origin !== window.location.origin) {
return false;
}
} catch {
return false;
}
const contentType = response.headers.get("content-type") ?? "";
if (contentType.includes(",") || contentType.split(";")[0].trim().toLowerCase() !== "text/html") {
return false;
}
return true;
};
var fetchPage = async (url, { html }) => {
try {
if (!html) {
const res = await window.fetch(url);
if (res.status !== 200) {
const requestUrl = new URL(url, window.location.href);
if (requestUrl.origin !== window.location.origin) {
return false;
}
const res = await window.fetch(requestUrl.href);
if (!isValidPageResponse(res)) {
return false;
}
html = await res.text();
@ -731,8 +752,8 @@ var fetchPage = async (url, { html }) => {
};
var preparePage = async (url, dom, { vdom } = {}) => {
dom.querySelectorAll("noscript").forEach((el) => el.remove());
const regions = {};
const regionsToAttach = {};
const regions = /* @__PURE__ */ Object.create(null);
const regionsToAttach = /* @__PURE__ */ Object.create(null);
dom.querySelectorAll(regionsSelector).forEach((region) => {
const { id, attachTo } = parseRegionAttribute(region);
if (region.parentElement.closest(`[${regionAttr}]`)) {
@ -762,7 +783,10 @@ var preparePage = async (url, dom, { vdom } = {}) => {
};
var renderPage = (page) => {
applyStyles(page.styles);
const regionsToAttach = { ...page.regionsToAttach };
const regionsToAttach = Object.assign(
/* @__PURE__ */ Object.create(null),
page.regionsToAttach
);
batch(() => {
populateServerData(page.initialData);
navigationSignal.value += 1;
@ -895,6 +919,7 @@ var { state, actions } = store("core/router", {
* @return Promise that resolves once the navigation is completed or aborted.
*/
*navigate(href, options = {}) {
options = Object.assign(/* @__PURE__ */ Object.create(null), options);
const { clientNavigationDisabled } = getConfig();
if (clientNavigationDisabled) {
yield forcePageReload(href);
@ -967,6 +992,7 @@ var { state, actions } = store("core/router", {
* @return Promise that resolves once the page has been fetched.
*/
*prefetch(url, options = {}) {
options = Object.assign(/* @__PURE__ */ Object.create(null), options);
const { clientNavigationDisabled } = getConfig();
if (clientNavigationDisabled) {
return;
@ -986,12 +1012,12 @@ state.url = state.url || window.location.href;
function a11ySpeak(messageKey) {
if (!hasLoadedNavigationTextsData) {
hasLoadedNavigationTextsData = true;
const content = document.getElementById(
"wp-script-module-data-@wordpress/interactivity-router"
)?.textContent;
if (content) {
const script = document.querySelector(
'script[id="wp-script-module-data-@wordpress/interactivity-router"]'
);
if (script instanceof HTMLScriptElement) {
try {
const parsed = JSON.parse(content);
const parsed = JSON.parse(script.text);
if (typeof parsed?.i18n?.loading === "string") {
navigationTexts.loading = parsed.i18n.loading;
}

View File

@ -1 +1 @@
<?php return array('dependencies' => array(), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'dynamic'), array('id' => '@wordpress/interactivity', 'import' => 'static')), 'version' => 'a6e90b8896f83fb1b5dd');
<?php return array('dependencies' => array(), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'dynamic'), array('id' => '@wordpress/interactivity', 'import' => 'static')), 'version' => 'dea5032c2153d213c1ee');

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More