diff options
Diffstat (limited to 'wp-admin/includes')
58 files changed, 1340 insertions, 660 deletions
diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 69f5fd4..30aab70 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -561,8 +561,8 @@ function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) { 'postId' => $comment ? $comment->comment_post_ID : '', /* translators: %s: Number of comments. */ 'total_items_i18n' => sprintf( _n( '%s item', '%s items', $total ), number_format_i18n( $total ) ), - 'total_pages' => ceil( $total / $per_page ), - 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ), + 'total_pages' => (int) ceil( $total / $per_page ), + 'total_pages_i18n' => number_format_i18n( (int) ceil( $total / $per_page ) ), 'total' => $total, 'time' => $time, 'in_moderation' => $counts->moderated, @@ -1628,8 +1628,13 @@ function wp_ajax_add_meta() { $post_data['post_type'] = $post->post_type; $post_data['post_status'] = 'draft'; $now = time(); - /* translators: 1: Post creation date, 2: Post creation time. */ - $post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdate( __( 'F j, Y' ), $now ), gmdate( __( 'g:i a' ), $now ) ); + + $post_data['post_title'] = sprintf( + /* translators: 1: Post creation date, 2: Post creation time. */ + __( 'Draft created on %1$s at %2$s' ), + gmdate( __( 'F j, Y' ), $now ), + gmdate( __( 'g:i a' ), $now ) + ); $pid = edit_post( $post_data ); @@ -3084,10 +3089,10 @@ function wp_ajax_query_attachments() { $posts_per_page = (int) $attachments_query->get( 'posts_per_page' ); - $max_pages = $posts_per_page ? ceil( $total_posts / $posts_per_page ) : 0; + $max_pages = $posts_per_page ? (int) ceil( $total_posts / $posts_per_page ) : 0; header( 'X-WP-Total: ' . (int) $total_posts ); - header( 'X-WP-TotalPages: ' . (int) $max_pages ); + header( 'X-WP-TotalPages: ' . $max_pages ); wp_send_json_success( $posts ); } @@ -4030,9 +4035,10 @@ function wp_ajax_crop_image() { } /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ - $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. - $attachment = $wp_site_icon->create_attachment_object( $cropped, $attachment_id ); - unset( $attachment['ID'] ); + $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. + + // Copy attachment properties. + $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context ); // Update the attachment. add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) ); @@ -4060,46 +4066,8 @@ function wp_ajax_crop_image() { /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. - $parent_url = wp_get_attachment_url( $attachment_id ); - $parent_basename = wp_basename( $parent_url ); - $url = str_replace( $parent_basename, wp_basename( $cropped ), $parent_url ); - - $size = wp_getimagesize( $cropped ); - $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; - - // Get the original image's post to pre-populate the cropped image. - $original_attachment = get_post( $attachment_id ); - $sanitized_post_title = sanitize_file_name( $original_attachment->post_title ); - $use_original_title = ( - ( '' !== trim( $original_attachment->post_title ) ) && - /* - * Check if the original image has a title other than the "filename" default, - * meaning the image had a title when originally uploaded or its title was edited. - */ - ( $parent_basename !== $sanitized_post_title ) && - ( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title ) - ); - $use_original_description = ( '' !== trim( $original_attachment->post_content ) ); - - $attachment = array( - 'post_title' => $use_original_title ? $original_attachment->post_title : wp_basename( $cropped ), - 'post_content' => $use_original_description ? $original_attachment->post_content : $url, - 'post_mime_type' => $image_type, - 'guid' => $url, - 'context' => $context, - ); - - // Copy the image caption attribute (post_excerpt field) from the original image. - if ( '' !== trim( $original_attachment->post_excerpt ) ) { - $attachment['post_excerpt'] = $original_attachment->post_excerpt; - } - - // Copy the image alt text attribute from the original image. - if ( '' !== trim( $original_attachment->_wp_attachment_image_alt ) ) { - $attachment['meta_input'] = array( - '_wp_attachment_image_alt' => wp_slash( $original_attachment->_wp_attachment_image_alt ), - ); - } + // Copy attachment properties. + $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, $context ); $attachment_id = wp_insert_attachment( $attachment, $cropped ); $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped ); @@ -4574,6 +4542,56 @@ function wp_ajax_install_plugin() { } /** + * Handles activating a plugin via AJAX. + * + * @since 6.5.0 + */ +function wp_ajax_activate_plugin() { + check_ajax_referer( 'updates' ); + + if ( empty( $_POST['name'] ) || empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) { + wp_send_json_error( + array( + 'slug' => '', + 'pluginName' => '', + 'plugin' => '', + 'errorCode' => 'no_plugin_specified', + 'errorMessage' => __( 'No plugin specified.' ), + ) + ); + } + + $status = array( + 'activate' => 'plugin', + 'slug' => wp_unslash( $_POST['slug'] ), + 'pluginName' => wp_unslash( $_POST['name'] ), + 'plugin' => wp_unslash( $_POST['plugin'] ), + ); + + if ( ! current_user_can( 'activate_plugin', $status['plugin'] ) ) { + $status['errorMessage'] = __( 'Sorry, you are not allowed to activate plugins on this site.' ); + wp_send_json_error( $status ); + } + + if ( is_plugin_active( $status['plugin'] ) ) { + $status['errorMessage'] = sprintf( + /* translators: %s: Plugin name. */ + __( '%s is already active.' ), + $status['pluginName'] + ); + } + + $activated = activate_plugin( $status['plugin'] ); + + if ( is_wp_error( $activated ) ) { + $status['errorMessage'] = $activated->get_error_message(); + wp_send_json_error( $status ); + } + + wp_send_json_success( $status ); +} + +/** * Handles updating a plugin via AJAX. * * @since 4.2.0 diff --git a/wp-admin/includes/class-custom-background.php b/wp-admin/includes/class-custom-background.php index 2eb3ccf..1d1cce7 100644 --- a/wp-admin/includes/class-custom-background.php +++ b/wp-admin/includes/class-custom-background.php @@ -42,8 +42,11 @@ class Custom_Background { * Constructor - Registers administration header callback. * * @since 3.0.0 - * @param callable $admin_header_callback - * @param callable $admin_image_div_callback Optional custom image div output callback. + * + * @param callable $admin_header_callback Optional. Administration header callback. + * Default empty string. + * @param callable $admin_image_div_callback Optional. Custom image div output callback. + * Default empty string. */ public function __construct( $admin_header_callback = '', $admin_image_div_callback = '' ) { $this->admin_header_callback = $admin_header_callback; diff --git a/wp-admin/includes/class-custom-image-header.php b/wp-admin/includes/class-custom-image-header.php index ee3bcb1..20f1959 100644 --- a/wp-admin/includes/class-custom-image-header.php +++ b/wp-admin/includes/class-custom-image-header.php @@ -47,11 +47,13 @@ class Custom_Image_Header { private $updated; /** - * Constructor - Register administration header callback. + * Constructor - Registers administration header callback. * * @since 2.1.0 - * @param callable $admin_header_callback - * @param callable $admin_image_div_callback Optional custom image div output callback. + * + * @param callable $admin_header_callback Administration header callback. + * @param callable $admin_image_div_callback Optional. Custom image div output callback. + * Default empty string. */ public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) { $this->admin_header_callback = $admin_header_callback; @@ -932,7 +934,7 @@ endif; <p class="hide-if-js"><strong><?php _e( 'You need JavaScript to choose a part of the image.' ); ?></strong></p> <div id="crop_image" style="position: relative"> - <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" alt="" /> + <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo esc_attr( $width ); ?>" height="<?php echo esc_attr( $height ); ?>" alt="" /> </div> <input type="hidden" name="x1" id="x1" value="0" /> @@ -1075,7 +1077,7 @@ endif; /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. - $attachment = $this->create_attachment_object( $cropped, $attachment_id ); + $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' ); if ( ! empty( $_POST['create-new-attachment'] ) ) { unset( $attachment['ID'] ); @@ -1312,12 +1314,14 @@ endif; * Creates an attachment 'object'. * * @since 3.9.0 + * @deprecated 6.5.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array An array with attachment object data. */ final public function create_attachment_object( $cropped, $parent_attachment_id ) { + _deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' ); $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); @@ -1419,7 +1423,7 @@ endif; /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. - $attachment = $this->create_attachment_object( $cropped, $attachment_id ); + $attachment = wp_copy_parent_attachment_properties( $cropped, $attachment_id, 'custom-header' ); $previous = $this->get_previous_crop( $attachment ); diff --git a/wp-admin/includes/class-file-upload-upgrader.php b/wp-admin/includes/class-file-upload-upgrader.php index e625615..1201c6d 100644 --- a/wp-admin/includes/class-file-upload-upgrader.php +++ b/wp-admin/includes/class-file-upload-upgrader.php @@ -70,24 +70,7 @@ class File_Upload_Upgrader { } if ( 'pluginzip' === $form || 'themezip' === $form ) { - $archive_is_valid = false; - - /** This filter is documented in wp-admin/includes/file.php */ - if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) { - $archive = new ZipArchive(); - $archive_is_valid = $archive->open( $file['file'], ZIPARCHIVE::CHECKCONS ); - - if ( true === $archive_is_valid ) { - $archive->close(); - } - } else { - require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; - - $archive = new PclZip( $file['file'] ); - $archive_is_valid = is_array( $archive->properties() ); - } - - if ( true !== $archive_is_valid ) { + if ( ! wp_zip_file_is_valid( $file['file'] ) ) { wp_delete_file( $file['file'] ); wp_die( __( 'Incompatible Archive.' ) ); } diff --git a/wp-admin/includes/class-ftp.php b/wp-admin/includes/class-ftp.php index 7658a0b..1b29783 100644 --- a/wp-admin/includes/class-ftp.php +++ b/wp-admin/includes/class-ftp.php @@ -483,7 +483,7 @@ class ftp_base { $this->PushError("restore", "cannot restore in ASCII mode"); return FALSE; } - if(!$this->_exec("REST ".$from, "resore")) return FALSE; + if(!$this->_exec("REST ".$from, "restore")) return FALSE; if(!$this->_checkCode()) return FALSE; return TRUE; } diff --git a/wp-admin/includes/class-language-pack-upgrader.php b/wp-admin/includes/class-language-pack-upgrader.php index 3c3d42a..855dbe6 100644 --- a/wp-admin/includes/class-language-pack-upgrader.php +++ b/wp-admin/includes/class-language-pack-upgrader.php @@ -409,12 +409,16 @@ class Language_Pack_Upgrader extends WP_Upgrader { $files = array( $remote_destination . $language_update->language . '.po', $remote_destination . $language_update->language . '.mo', + $remote_destination . $language_update->language . '.l10n.php', $remote_destination . 'admin-' . $language_update->language . '.po', $remote_destination . 'admin-' . $language_update->language . '.mo', + $remote_destination . 'admin-' . $language_update->language . '.l10n.php', $remote_destination . 'admin-network-' . $language_update->language . '.po', $remote_destination . 'admin-network-' . $language_update->language . '.mo', + $remote_destination . 'admin-network-' . $language_update->language . '.l10n.php', $remote_destination . 'continents-cities-' . $language_update->language . '.po', $remote_destination . 'continents-cities-' . $language_update->language . '.mo', + $remote_destination . 'continents-cities-' . $language_update->language . '.l10n.php', ); $json_translation_files = glob( $language_directory . $language_update->language . '-*.json' ); @@ -427,6 +431,7 @@ class Language_Pack_Upgrader extends WP_Upgrader { $files = array( $remote_destination . $language_update->slug . '-' . $language_update->language . '.po', $remote_destination . $language_update->slug . '-' . $language_update->language . '.mo', + $remote_destination . $language_update->slug . '-' . $language_update->language . '.l10n.php', ); $language_directory = $language_directory . $language_update->type . 's/'; diff --git a/wp-admin/includes/class-pclzip.php b/wp-admin/includes/class-pclzip.php index 3fdade5..963f311 100644 --- a/wp-admin/includes/class-pclzip.php +++ b/wp-admin/includes/class-pclzip.php @@ -1854,7 +1854,7 @@ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit_int*PCLZIP_TEMPORARY_FILE_RATIO); - // ----- Sanity check : No threshold if value lower than 1M + // ----- Confidence check : No threshold if value lower than 1M if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); } diff --git a/wp-admin/includes/class-plugin-installer-skin.php b/wp-admin/includes/class-plugin-installer-skin.php index ed165ed..20cd15f 100644 --- a/wp-admin/includes/class-plugin-installer-skin.php +++ b/wp-admin/includes/class-plugin-installer-skin.php @@ -121,7 +121,7 @@ class Plugin_Installer_Skin extends WP_Upgrader_Skin { $install_actions['network_activate'] = sprintf( '<a class="button button-primary" href="%s" target="_parent">%s</a>', wp_nonce_url( 'plugins.php?action=activate&networkwide=1&plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ), - __( 'Network Activate' ) + _x( 'Network Activate', 'plugin' ) ); unset( $install_actions['activate_plugin'] ); } diff --git a/wp-admin/includes/class-plugin-upgrader.php b/wp-admin/includes/class-plugin-upgrader.php index 02743f6..091cfeb 100644 --- a/wp-admin/includes/class-plugin-upgrader.php +++ b/wp-admin/includes/class-plugin-upgrader.php @@ -472,7 +472,7 @@ class Plugin_Upgrader extends WP_Upgrader { } $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source ); - if ( ! is_dir( $working_directory ) ) { // Sanity check, if the above fails, let's not prevent installation. + if ( ! is_dir( $working_directory ) ) { // Confidence check, if the above fails, let's not prevent installation. return $source; } diff --git a/wp-admin/includes/class-theme-installer-skin.php b/wp-admin/includes/class-theme-installer-skin.php index 99fe322..d83e038 100644 --- a/wp-admin/includes/class-theme-installer-skin.php +++ b/wp-admin/includes/class-theme-installer-skin.php @@ -138,7 +138,7 @@ class Theme_Installer_Skin extends WP_Upgrader_Skin { '<a href="%s" class="activatelink">' . '<span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>', esc_url( $activate_link ), - __( 'Activate' ), + _x( 'Activate', 'theme' ), /* translators: Hidden accessibility text. %s: Theme name. */ sprintf( _x( 'Activate “%s”', 'theme' ), $name ) ); diff --git a/wp-admin/includes/class-theme-upgrader-skin.php b/wp-admin/includes/class-theme-upgrader-skin.php index 97d76a8..cd4c6c6 100644 --- a/wp-admin/includes/class-theme-upgrader-skin.php +++ b/wp-admin/includes/class-theme-upgrader-skin.php @@ -110,7 +110,7 @@ class Theme_Upgrader_Skin extends WP_Upgrader_Skin { '<a href="%s" class="activatelink">' . '<span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>', esc_url( $activate_link ), - __( 'Activate' ), + _x( 'Activate', 'theme' ), /* translators: Hidden accessibility text. %s: Theme name. */ sprintf( _x( 'Activate “%s”', 'theme' ), $name ) ); diff --git a/wp-admin/includes/class-theme-upgrader.php b/wp-admin/includes/class-theme-upgrader.php index 12bd477..869bf64 100644 --- a/wp-admin/includes/class-theme-upgrader.php +++ b/wp-admin/includes/class-theme-upgrader.php @@ -371,6 +371,8 @@ class Theme_Upgrader extends WP_Upgrader { * @since 3.0.0 * @since 3.7.0 The `$args` parameter was added, making clearing the update cache optional. * + * @global string $wp_version The WordPress version string. + * * @param string[] $themes Array of the theme slugs. * @param array $args { * Optional. Other arguments for upgrading several themes at once. Default empty array. @@ -381,6 +383,8 @@ class Theme_Upgrader extends WP_Upgrader { * @return array[]|false An array of results, or false if unable to connect to the filesystem. */ public function bulk_upgrade( $themes, $args = array() ) { + global $wp_version; + $defaults = array( 'clear_update_cache' => true, ); @@ -442,23 +446,55 @@ class Theme_Upgrader extends WP_Upgrader { // Get the URL to the zip file. $r = $current->response[ $theme ]; - $result = $this->run( - array( - 'package' => $r['package'], - 'destination' => get_theme_root( $theme ), - 'clear_destination' => true, - 'clear_working' => true, - 'is_multi' => true, - 'hook_extra' => array( - 'theme' => $theme, - 'temp_backup' => array( - 'slug' => $theme, - 'src' => get_theme_root( $theme ), - 'dir' => 'themes', + if ( isset( $r['requires'] ) && ! is_wp_version_compatible( $r['requires'] ) ) { + $result = new WP_Error( + 'incompatible_wp_required_version', + sprintf( + /* translators: 1: Current WordPress version, 2: WordPress version required by the new theme version. */ + __( 'Your WordPress version is %1$s, however the new theme version requires %2$s.' ), + $wp_version, + $r['requires'] + ) + ); + + $this->skin->before( $result ); + $this->skin->error( $result ); + $this->skin->after(); + } elseif ( isset( $r['requires_php'] ) && ! is_php_version_compatible( $r['requires_php'] ) ) { + $result = new WP_Error( + 'incompatible_php_required_version', + sprintf( + /* translators: 1: Current PHP version, 2: PHP version required by the new theme version. */ + __( 'The PHP version on your server is %1$s, however the new theme version requires %2$s.' ), + PHP_VERSION, + $r['requires_php'] + ) + ); + + $this->skin->before( $result ); + $this->skin->error( $result ); + $this->skin->after(); + } else { + add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); + $result = $this->run( + array( + 'package' => $r['package'], + 'destination' => get_theme_root( $theme ), + 'clear_destination' => true, + 'clear_working' => true, + 'is_multi' => true, + 'hook_extra' => array( + 'theme' => $theme, + 'temp_backup' => array( + 'slug' => $theme, + 'src' => get_theme_root( $theme ), + 'dir' => 'themes', + ), ), - ), - ) - ); + ) + ); + remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) ); + } $results[ $theme ] = $result; @@ -538,7 +574,7 @@ class Theme_Upgrader extends WP_Upgrader { // Check that the folder contains a valid theme. $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit( WP_CONTENT_DIR ), $source ); - if ( ! is_dir( $working_directory ) ) { // Sanity check, if the above fails, let's not prevent installation. + if ( ! is_dir( $working_directory ) ) { // Confidence check, if the above fails, let's not prevent installation. return $source; } diff --git a/wp-admin/includes/class-wp-application-passwords-list-table.php b/wp-admin/includes/class-wp-application-passwords-list-table.php index 6c0bf26..9a60853 100644 --- a/wp-admin/includes/class-wp-application-passwords-list-table.php +++ b/wp-admin/includes/class-wp-application-passwords-list-table.php @@ -146,7 +146,7 @@ class WP_Application_Passwords_List_Table extends WP_List_Table { * * @since 5.6.0 * - * @param string $which The location of the bulk actions: 'top' or 'bottom'. + * @param string $which The location of the bulk actions: Either 'top' or 'bottom'. */ protected function display_tablenav( $which ) { ?> diff --git a/wp-admin/includes/class-wp-comments-list-table.php b/wp-admin/includes/class-wp-comments-list-table.php index 1433818..d4970e2 100644 --- a/wp-admin/includes/class-wp-comments-list-table.php +++ b/wp-admin/includes/class-wp-comments-list-table.php @@ -437,7 +437,7 @@ class WP_Comments_List_Table extends WP_List_Table { * @since 5.6.0 The `$which` parameter was added. * * @param string $comment_status The comment status name. Default 'All'. - * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. + * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'manage_comments_nav', $comment_status, $which ); @@ -638,8 +638,23 @@ class WP_Comments_List_Table extends WP_List_Table { public function single_row( $item ) { global $post, $comment; + // Restores the more descriptive, specific name for use within this method. $comment = $item; + if ( $comment->comment_post_ID > 0 ) { + $post = get_post( $comment->comment_post_ID ); + } + + $edit_post_cap = $post ? 'edit_post' : 'edit_posts'; + + if ( ! current_user_can( $edit_post_cap, $comment->comment_post_ID ) + && ( post_password_required( $comment->comment_post_ID ) + || ! current_user_can( 'read_post', $comment->comment_post_ID ) ) + ) { + // The user has no access to the post and thus cannot see the comments. + return false; + } + $the_comment_class = wp_get_comment_status( $comment ); if ( ! $the_comment_class ) { @@ -648,25 +663,8 @@ class WP_Comments_List_Table extends WP_List_Table { $the_comment_class = implode( ' ', get_comment_class( $the_comment_class, $comment, $comment->comment_post_ID ) ); - if ( $comment->comment_post_ID > 0 ) { - $post = get_post( $comment->comment_post_ID ); - } - $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID ); - $edit_post_cap = $post ? 'edit_post' : 'edit_posts'; - if ( - current_user_can( $edit_post_cap, $comment->comment_post_ID ) || - ( - empty( $post->post_password ) && - current_user_can( 'read_post', $comment->comment_post_ID ) - ) - ) { - // The user has access to the post - } else { - return false; - } - echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>"; $this->single_row_columns( $comment ); echo "</tr>\n"; diff --git a/wp-admin/includes/class-wp-debug-data.php b/wp-admin/includes/class-wp-debug-data.php index d83c873..ed6a9e7 100644 --- a/wp-admin/includes/class-wp-debug-data.php +++ b/wp-admin/includes/class-wp-debug-data.php @@ -381,6 +381,14 @@ class WP_Debug_Data { // Conditionally add debug information for multisite setups. if ( is_multisite() ) { + $site_id = get_current_blog_id(); + + $info['wp-core']['fields']['site_id'] = array( + 'label' => __( 'Site ID' ), + 'value' => $site_id, + 'debug' => $site_id, + ); + $network_query = new WP_Network_Query(); $network_ids = $network_query->query( array( diff --git a/wp-admin/includes/class-wp-filesystem-base.php b/wp-admin/includes/class-wp-filesystem-base.php index 8b29127..125c2d3 100644 --- a/wp-admin/includes/class-wp-filesystem-base.php +++ b/wp-admin/includes/class-wp-filesystem-base.php @@ -836,7 +836,7 @@ class WP_Filesystem_Base { * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * - * @type array $0... { + * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. diff --git a/wp-admin/includes/class-wp-filesystem-direct.php b/wp-admin/includes/class-wp-filesystem-direct.php index 9fdfeb9..2efd5b0 100644 --- a/wp-admin/includes/class-wp-filesystem-direct.php +++ b/wp-admin/includes/class-wp-filesystem-direct.php @@ -599,7 +599,7 @@ class WP_Filesystem_Direct extends WP_Filesystem_Base { * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * - * @type array $0... { + * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. diff --git a/wp-admin/includes/class-wp-filesystem-ftpext.php b/wp-admin/includes/class-wp-filesystem-ftpext.php index 7db0685..0294720 100644 --- a/wp-admin/includes/class-wp-filesystem-ftpext.php +++ b/wp-admin/includes/class-wp-filesystem-ftpext.php @@ -731,7 +731,7 @@ class WP_Filesystem_FTPext extends WP_Filesystem_Base { * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * - * @type array $0... { + * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. diff --git a/wp-admin/includes/class-wp-filesystem-ftpsockets.php b/wp-admin/includes/class-wp-filesystem-ftpsockets.php index c69d801..9a37d88 100644 --- a/wp-admin/includes/class-wp-filesystem-ftpsockets.php +++ b/wp-admin/includes/class-wp-filesystem-ftpsockets.php @@ -625,7 +625,7 @@ class WP_Filesystem_ftpsockets extends WP_Filesystem_Base { * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * - * @type array $0... { + * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. diff --git a/wp-admin/includes/class-wp-filesystem-ssh2.php b/wp-admin/includes/class-wp-filesystem-ssh2.php index d68f143..9e0cb88 100644 --- a/wp-admin/includes/class-wp-filesystem-ssh2.php +++ b/wp-admin/includes/class-wp-filesystem-ssh2.php @@ -4,9 +4,9 @@ * * To use this class you must follow these steps for PHP 5.2.6+ * - * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes + * {@link http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes} * - * Compile libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work) + * Compile libssh2 (Note: Only 0.14 is officially working with PHP 5.2.6+ right now, But many users have found the latest versions work) * * cd /usr/src * wget https://www.libssh2.org/download/libssh2-0.14.tar.gz @@ -745,7 +745,7 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { * @return array|false { * Array of arrays containing file information. False if unable to list directory contents. * - * @type array $0... { + * @type array ...$0 { * Array of file information. Note that some elements may not be available on all filesystems. * * @type string $name Name of the file or directory. diff --git a/wp-admin/includes/class-wp-list-table.php b/wp-admin/includes/class-wp-list-table.php index b3aebd9..4e6aaa4 100644 --- a/wp-admin/includes/class-wp-list-table.php +++ b/wp-admin/includes/class-wp-list-table.php @@ -319,7 +319,7 @@ class WP_List_Table { ); if ( ! $args['total_pages'] && $args['per_page'] > 0 ) { - $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] ); + $args['total_pages'] = (int) ceil( $args['total_items'] / $args['per_page'] ); } // Redirect if page number is invalid and headers are not already sent. @@ -564,7 +564,7 @@ class WP_List_Table { * * @since 3.1.0 * - * @param string $which The location of the bulk actions: 'top' or 'bottom'. + * @param string $which The location of the bulk actions: Either 'top' or 'bottom'. * This is designated as optional for backward compatibility. */ protected function bulk_actions( $which = '' ) { @@ -828,6 +828,17 @@ class WP_List_Table { * @param int $pending_comments Number of pending comments. */ protected function comments_bubble( $post_id, $pending_comments ) { + $post_object = get_post( $post_id ); + $edit_post_cap = $post_object ? 'edit_post' : 'edit_posts'; + + if ( ! current_user_can( $edit_post_cap, $post_id ) + && ( post_password_required( $post_id ) + || ! current_user_can( 'read_post', $post_id ) ) + ) { + // The user has no access to the post and thus cannot see the comments. + return false; + } + $approved_comments = get_comments_number(); $approved_comments_number = number_format_i18n( $approved_comments ); @@ -851,20 +862,6 @@ class WP_List_Table { $pending_comments_number ); - $post_object = get_post( $post_id ); - $edit_post_cap = $post_object ? 'edit_post' : 'edit_posts'; - if ( - current_user_can( $edit_post_cap, $post_id ) || - ( - empty( $post_object->post_password ) && - current_user_can( 'read_post', $post_id ) - ) - ) { - // The user has access to the post and thus can see comments - } else { - return false; - } - if ( ! $approved_comments && ! $pending_comments ) { // No comments at all. printf( @@ -1015,7 +1012,7 @@ class WP_List_Table { * * @since 3.1.0 * - * @param string $which + * @param string $which The location of the pagination: Either 'top' or 'bottom'. */ protected function pagination( $which ) { if ( empty( $this->_pagination_args ) ) { @@ -1666,7 +1663,7 @@ class WP_List_Table { * Generates the table navigation above or below the table * * @since 3.1.0 - * @param string $which + * @param string $which The location of the navigation: Either 'top' or 'bottom'. */ protected function display_tablenav( $which ) { if ( 'top' === $which ) { diff --git a/wp-admin/includes/class-wp-ms-sites-list-table.php b/wp-admin/includes/class-wp-ms-sites-list-table.php index ffa2231..c28a454 100644 --- a/wp-admin/includes/class-wp-ms-sites-list-table.php +++ b/wp-admin/includes/class-wp-ms-sites-list-table.php @@ -302,7 +302,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table { /** * @global string $mode List table view mode. * - * @param string $which The location of the pagination nav markup: 'top' or 'bottom'. + * @param string $which The location of the pagination nav markup: Either 'top' or 'bottom'. */ protected function pagination( $which ) { global $mode; @@ -319,7 +319,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table { * * @since 5.3.0 * - * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. + * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { ?> @@ -333,7 +333,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table { * * @since 5.3.0 * - * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. + * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'restrict_manage_sites', $which ); @@ -353,7 +353,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table { * * @since 5.3.0 * - * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. + * @param string $which The location of the extra table nav markup: Either 'top' or 'bottom'. */ do_action( 'manage_sites_extra_tablenav', $which ); } @@ -756,7 +756,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table { 'activateblog_' . $blog['blog_id'] ) ), - __( 'Activate' ) + _x( 'Activate', 'site' ) ); } else { $actions['deactivate'] = sprintf( diff --git a/wp-admin/includes/class-wp-ms-users-list-table.php b/wp-admin/includes/class-wp-ms-users-list-table.php index ec12321..d02d380 100644 --- a/wp-admin/includes/class-wp-ms-users-list-table.php +++ b/wp-admin/includes/class-wp-ms-users-list-table.php @@ -383,25 +383,30 @@ class WP_MS_Users_List_Table extends WP_List_Table { $path = ( '/' === $site->path ) ? '' : $site->path; $site_classes = array( 'site-' . $site->site_id ); + /** - * Filters the span class for a site listing on the mulisite user list table. + * Filters the span class for a site listing on the multisite user list table. * * @since 5.2.0 * - * @param string[] $site_classes Array of class names used within the span tag. Default "site-#" with the site's network ID. + * @param string[] $site_classes Array of class names used within the span tag. + * Default "site-#" with the site's network ID. * @param int $site_id Site ID. * @param int $network_id Network ID. * @param WP_User $user WP_User object. */ $site_classes = apply_filters( 'ms_user_list_site_class', $site_classes, $site->userblog_id, $site->site_id, $user ); + if ( is_array( $site_classes ) && ! empty( $site_classes ) ) { $site_classes = array_map( 'sanitize_html_class', array_unique( $site_classes ) ); echo '<span class="' . esc_attr( implode( ' ', $site_classes ) ) . '">'; } else { echo '<span>'; } + echo '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $site->userblog_id ) ) . '">' . str_replace( '.' . get_network()->domain, '', $site->domain . $path ) . '</a>'; echo ' <small class="row-actions">'; + $actions = array(); $actions['edit'] = '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $site->userblog_id ) ) . '">' . __( 'Edit' ) . '</a>'; diff --git a/wp-admin/includes/class-wp-plugin-install-list-table.php b/wp-admin/includes/class-wp-plugin-install-list-table.php index 7823f00..f3452a7 100644 --- a/wp-admin/includes/class-wp-plugin-install-list-table.php +++ b/wp-admin/includes/class-wp-plugin-install-list-table.php @@ -555,102 +555,7 @@ class WP_Plugin_Install_List_Table extends WP_List_Table { $action_links = array(); - if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) { - $status = install_plugin_install_status( $plugin ); - - switch ( $status['status'] ) { - case 'install': - if ( $status['url'] ) { - if ( $compatible_php && $compatible_wp ) { - $action_links[] = sprintf( - '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>', - esc_attr( $plugin['slug'] ), - esc_url( $status['url'] ), - /* translators: %s: Plugin name and version. */ - esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ), - esc_attr( $name ), - __( 'Install Now' ) - ); - } else { - $action_links[] = sprintf( - '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', - _x( 'Cannot Install', 'plugin' ) - ); - } - } - break; - - case 'update_available': - if ( $status['url'] ) { - if ( $compatible_php && $compatible_wp ) { - $action_links[] = sprintf( - '<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>', - esc_attr( $status['file'] ), - esc_attr( $plugin['slug'] ), - esc_url( $status['url'] ), - /* translators: %s: Plugin name and version. */ - esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ), - esc_attr( $name ), - __( 'Update Now' ) - ); - } else { - $action_links[] = sprintf( - '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', - _x( 'Cannot Update', 'plugin' ) - ); - } - } - break; - - case 'latest_installed': - case 'newer_installed': - if ( is_plugin_active( $status['file'] ) ) { - $action_links[] = sprintf( - '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', - _x( 'Active', 'plugin' ) - ); - } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) { - if ( $compatible_php && $compatible_wp ) { - $button_text = __( 'Activate' ); - /* translators: %s: Plugin name. */ - $button_label = _x( 'Activate %s', 'plugin' ); - $activate_url = add_query_arg( - array( - '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), - 'action' => 'activate', - 'plugin' => $status['file'], - ), - network_admin_url( 'plugins.php' ) - ); - - if ( is_network_admin() ) { - $button_text = __( 'Network Activate' ); - /* translators: %s: Plugin name. */ - $button_label = _x( 'Network Activate %s', 'plugin' ); - $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url ); - } - - $action_links[] = sprintf( - '<a href="%1$s" class="button activate-now" aria-label="%2$s">%3$s</a>', - esc_url( $activate_url ), - esc_attr( sprintf( $button_label, $plugin['name'] ) ), - $button_text - ); - } else { - $action_links[] = sprintf( - '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', - _x( 'Cannot Activate', 'plugin' ) - ); - } - } else { - $action_links[] = sprintf( - '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', - _x( 'Installed', 'plugin' ) - ); - } - break; - } - } + $action_links[] = wp_get_plugin_action_button( $name, $plugin, $compatible_php, $compatible_wp ); $details_link = self_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin['slug'] . @@ -769,6 +674,12 @@ class WP_Plugin_Install_List_Table extends WP_List_Table { <p class="authors"><?php echo $author; ?></p> </div> </div> + <?php + $dependencies_notice = $this->get_dependencies_notice( $plugin ); + if ( ! empty( $dependencies_notice ) ) { + echo $dependencies_notice; + } + ?> <div class="plugin-card-bottom"> <div class="vers column-rating"> <?php @@ -828,4 +739,90 @@ class WP_Plugin_Install_List_Table extends WP_List_Table { echo '</div></div>'; } } + + /** + * Returns a notice containing a list of dependencies required by the plugin. + * + * @since 6.5.0 + * + * @param array $plugin_data An array of plugin data. See {@see plugins_api()} + * for the list of possible values. + * @return string A notice containing a list of dependencies required by the plugin, + * or an empty string if none is required. + */ + protected function get_dependencies_notice( $plugin_data ) { + if ( empty( $plugin_data['requires_plugins'] ) ) { + return ''; + } + + $no_name_markup = '<div class="plugin-dependency"><span class="plugin-dependency-name">%s</span></div>'; + $has_name_markup = '<div class="plugin-dependency"><span class="plugin-dependency-name">%s</span> %s</div>'; + + $dependencies_list = ''; + foreach ( $plugin_data['requires_plugins'] as $dependency ) { + $dependency_data = WP_Plugin_Dependencies::get_dependency_data( $dependency ); + + if ( + false !== $dependency_data && + ! empty( $dependency_data['name'] ) && + ! empty( $dependency_data['slug'] ) && + ! empty( $dependency_data['version'] ) + ) { + $more_details_link = $this->get_more_details_link( $dependency_data['name'], $dependency_data['slug'] ); + $dependencies_list .= sprintf( $has_name_markup, esc_html( $dependency_data['name'] ), $more_details_link ); + continue; + } + + $result = plugins_api( 'plugin_information', array( 'slug' => $dependency ) ); + + if ( ! empty( $result->name ) ) { + $more_details_link = $this->get_more_details_link( $result->name, $result->slug ); + $dependencies_list .= sprintf( $has_name_markup, esc_html( $result->name ), $more_details_link ); + continue; + } + + $dependencies_list .= sprintf( $no_name_markup, esc_html( $dependency ) ); + } + + $dependencies_notice = sprintf( + '<div class="plugin-dependencies notice notice-alt notice-info inline"><p class="plugin-dependencies-explainer-text">%s</p> %s</div>', + '<strong>' . __( 'Additional plugins are required' ) . '</strong>', + $dependencies_list + ); + + return $dependencies_notice; + } + + /** + * Creates a 'More details' link for the plugin. + * + * @since 6.5.0 + * + * @param string $name The plugin's name. + * @param string $slug The plugin's slug. + * @return string The 'More details' link for the plugin. + */ + protected function get_more_details_link( $name, $slug ) { + $url = add_query_arg( + array( + 'tab' => 'plugin-information', + 'plugin' => $slug, + 'TB_iframe' => 'true', + 'width' => '600', + 'height' => '550', + ), + network_admin_url( 'plugin-install.php' ) + ); + + $more_details_link = sprintf( + '<a href="%1$s" class="more-details-link thickbox open-plugin-details-modal" aria-label="%2$s" data-title="%3$s">%4$s</a>', + esc_url( $url ), + /* translators: %s: Plugin name. */ + sprintf( __( 'More information about %s' ), esc_html( $name ) ), + esc_attr( $name ), + __( 'More Details' ) + ); + + return $more_details_link; + } } diff --git a/wp-admin/includes/class-wp-plugins-list-table.php b/wp-admin/includes/class-wp-plugins-list-table.php index 5c92fba..4cc0132 100644 --- a/wp-admin/includes/class-wp-plugins-list-table.php +++ b/wp-admin/includes/class-wp-plugins-list-table.php @@ -607,11 +607,11 @@ class WP_Plugins_List_Table extends WP_List_Table { $actions = array(); if ( 'active' !== $status ) { - $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' ); + $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' ); } if ( 'inactive' !== $status && 'recent' !== $status ) { - $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' ); + $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Deactivate', 'plugin' ) : _x( 'Deactivate', 'plugin' ); } if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) { @@ -754,6 +754,11 @@ class WP_Plugins_List_Table extends WP_List_Table { $compatible_php = is_php_version_compatible( $requires_php ); $compatible_wp = is_wp_version_compatible( $requires_wp ); + $has_dependents = WP_Plugin_Dependencies::has_dependents( $plugin_file ); + $has_active_dependents = WP_Plugin_Dependencies::has_active_dependents( $plugin_file ); + $has_unmet_dependencies = WP_Plugin_Dependencies::has_unmet_dependencies( $plugin_file ); + $has_circular_dependency = WP_Plugin_Dependencies::has_circular_dependency( $plugin_file ); + if ( 'mustuse' === $context ) { $is_active = true; } elseif ( 'dropins' === $context ) { @@ -796,26 +801,53 @@ class WP_Plugins_List_Table extends WP_List_Table { if ( $screen->in_admin( 'network' ) ) { if ( $is_active ) { if ( current_user_can( 'manage_network_plugins' ) ) { - $actions['deactivate'] = sprintf( - '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Network Deactivate' ) - ); + if ( $has_active_dependents ) { + $actions['deactivate'] = __( 'Deactivate' ) . + '<span class="screen-reader-text">' . + __( 'You cannot deactivate this plugin as other plugins require it.' ) . + '</span>'; + + } else { + $deactivate_url = 'plugins.php?action=deactivate' . + '&plugin=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['deactivate'] = sprintf( + '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>', + wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ), + _x( 'Network Deactivate', 'plugin' ) + ); + } } } else { if ( current_user_can( 'manage_network_plugins' ) ) { if ( $compatible_php && $compatible_wp ) { - $actions['activate'] = sprintf( - '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Network Activate' ) - ); + if ( $has_unmet_dependencies ) { + $actions['activate'] = _x( 'Network Activate', 'plugin' ) . + '<span class="screen-reader-text">' . + __( 'You cannot activate this plugin as it has unmet requirements.' ) . + '</span>'; + } else { + $activate_url = 'plugins.php?action=activate' . + '&plugin=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['activate'] = sprintf( + '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>', + wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ), + _x( 'Network Activate', 'plugin' ) + ); + } } else { $actions['activate'] = sprintf( '<span>%s</span>', @@ -825,14 +857,27 @@ class WP_Plugins_List_Table extends WP_List_Table { } if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) { - $actions['delete'] = sprintf( - '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Delete' ) - ); + if ( $has_dependents && ! $has_circular_dependency ) { + $actions['delete'] = __( 'Delete' ) . + '<span class="screen-reader-text">' . + __( 'You cannot delete this plugin as other plugins require it.' ) . + '</span>'; + } else { + $delete_url = 'plugins.php?action=delete-selected' . + '&checked[]=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['delete'] = sprintf( + '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>', + wp_nonce_url( $delete_url, 'bulk-plugins' ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), + __( 'Delete' ) + ); + } } } } else { @@ -846,20 +891,39 @@ class WP_Plugins_List_Table extends WP_List_Table { ); } elseif ( $is_active ) { if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) { - $actions['deactivate'] = sprintf( - '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Deactivate' ) - ); + if ( $has_active_dependents ) { + $actions['deactivate'] = __( 'Deactivate' ) . + '<span class="screen-reader-text">' . + __( 'You cannot deactivate this plugin as other plugins depend on it.' ) . + '</span>'; + } else { + $deactivate_url = 'plugins.php?action=deactivate' . + '&plugin=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['deactivate'] = sprintf( + '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>', + wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ), + __( 'Deactivate' ) + ); + } } if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) { + $resume_url = 'plugins.php?action=resume' . + '&plugin=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + $actions['resume'] = sprintf( '<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=resume&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'resume-plugin_' . $plugin_file ), + wp_nonce_url( $resume_url, 'resume-plugin_' . $plugin_file ), esc_attr( $plugin_id_attr ), /* translators: %s: Plugin name. */ esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ), @@ -869,14 +933,27 @@ class WP_Plugins_List_Table extends WP_List_Table { } else { if ( current_user_can( 'activate_plugin', $plugin_file ) ) { if ( $compatible_php && $compatible_wp ) { - $actions['activate'] = sprintf( - '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Activate' ) - ); + if ( $has_unmet_dependencies ) { + $actions['activate'] = _x( 'Activate', 'plugin' ) . + '<span class="screen-reader-text">' . + __( 'You cannot activate this plugin as it has unmet requirements.' ) . + '</span>'; + } else { + $activate_url = 'plugins.php?action=activate' . + '&plugin=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['activate'] = sprintf( + '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>', + wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ), + _x( 'Activate', 'plugin' ) + ); + } } else { $actions['activate'] = sprintf( '<span>%s</span>', @@ -886,14 +963,27 @@ class WP_Plugins_List_Table extends WP_List_Table { } if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) { - $actions['delete'] = sprintf( - '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>', - wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Delete' ) - ); + if ( $has_dependents && ! $has_circular_dependency ) { + $actions['delete'] = __( 'Delete' ) . + '<span class="screen-reader-text">' . + __( 'You cannot delete this plugin as other plugins require it.' ) . + '</span>'; + } else { + $delete_url = 'plugins.php?action=delete-selected' . + '&checked[]=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; + + $actions['delete'] = sprintf( + '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>', + wp_nonce_url( $delete_url, 'bulk-plugins' ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), + __( 'Delete' ) + ); + } } } // End if $is_active. } // End if $screen->in_admin( 'network' ). @@ -988,17 +1078,28 @@ class WP_Plugins_List_Table extends WP_List_Table { $class = $is_active ? 'active' : 'inactive'; $checkbox_id = 'checkbox_' . md5( $plugin_file ); + $disabled = ''; + + if ( $has_dependents || $has_unmet_dependencies ) { + $disabled = 'disabled'; + } - if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) { + if ( + $restrict_network_active || + $restrict_network_only || + in_array( $status, array( 'mustuse', 'dropins' ), true ) || + ! $compatible_php + ) { $checkbox = ''; } else { $checkbox = sprintf( - '<input type="checkbox" name="checked[]" value="%1$s" id="%2$s" />' . - '<label for="%2$s"><span class="screen-reader-text">%3$s</span></label>', - esc_attr( $plugin_file ), + '<label class="label-covers-full-cell" for="%1$s">' . + '<span class="screen-reader-text">%2$s</span></label>' . + '<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" ' . $disabled . '/>', $checkbox_id, /* translators: Hidden accessibility text. %s: Plugin name. */ - sprintf( __( 'Select %s' ), $plugin_data['Name'] ) + sprintf( __( 'Select %s' ), $plugin_data['Name'] ), + esc_attr( $plugin_file ) ); } @@ -1007,8 +1108,11 @@ class WP_Plugins_List_Table extends WP_List_Table { $plugin_name = $plugin_data['Name']; } - if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) - || ! $compatible_php || ! $compatible_wp + if ( + ! empty( $totals['upgrade'] ) && + ! empty( $plugin_data['update'] ) || + ! $compatible_php || + ! $compatible_wp ) { $class .= ' update'; } @@ -1057,15 +1161,19 @@ class WP_Plugins_List_Table extends WP_List_Table { <div class='$class second plugin-version-author-uri'>"; $plugin_meta = array(); + if ( ! empty( $plugin_data['Version'] ) ) { /* translators: %s: Plugin version number. */ $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] ); } + if ( ! empty( $plugin_data['Author'] ) ) { $author = $plugin_data['Author']; + if ( ! empty( $plugin_data['AuthorURI'] ) ) { $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>'; } + /* translators: %s: Plugin author name. */ $plugin_meta[] = sprintf( __( 'By %s' ), $author ); } @@ -1149,6 +1257,24 @@ class WP_Plugins_List_Table extends WP_List_Table { echo '</div>'; + if ( $has_dependents ) { + $this->add_dependents_to_dependency_plugin_row( $plugin_file ); + } + + if ( WP_Plugin_Dependencies::has_dependencies( $plugin_file ) ) { + $this->add_dependencies_to_dependent_plugin_row( $plugin_file ); + } + + /** + * Fires after plugin row meta. + * + * @since 6.5.0 + * + * @param string $plugin_file Refer to {@see 'plugin_row_meta'} filter. + * @param array $plugin_data Refer to {@see 'plugin_row_meta'} filter. + */ + do_action( 'after_plugin_row_meta', $plugin_file, $plugin_data ); + if ( $paused ) { $notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' ); @@ -1391,4 +1517,140 @@ class WP_Plugins_List_Table extends WP_List_Table { protected function get_primary_column_name() { return 'name'; } + + /** + * Prints a list of other plugins that depend on the plugin. + * + * @since 6.5.0 + * + * @param string $dependency The dependency's filepath, relative to the plugins directory. + */ + protected function add_dependents_to_dependency_plugin_row( $dependency ) { + $dependent_names = WP_Plugin_Dependencies::get_dependent_names( $dependency ); + + if ( empty( $dependent_names ) ) { + return; + } + + $dependency_note = __( 'Note: This plugin cannot be deactivated or deleted until the plugins that require it are deactivated or deleted.' ); + + $comma = wp_get_list_item_separator(); + $required_by = sprintf( + /* translators: %s: List of dependencies. */ + __( '<strong>Required by:</strong> %s' ), + implode( $comma, $dependent_names ) + ); + + printf( + '<div class="required-by"><p>%1$s</p><p>%2$s</p></div>', + $required_by, + $dependency_note + ); + } + + /** + * Prints a list of other plugins that the plugin depends on. + * + * @since 6.5.0 + * + * @param string $dependent The dependent plugin's filepath, relative to the plugins directory. + */ + protected function add_dependencies_to_dependent_plugin_row( $dependent ) { + $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $dependent ); + + if ( array() === $dependency_names ) { + return; + } + + $links = array(); + foreach ( $dependency_names as $slug => $name ) { + $links[] = $this->get_dependency_view_details_link( $name, $slug ); + } + + $is_active = is_multisite() ? is_plugin_active_for_network( $dependent ) : is_plugin_active( $dependent ); + $comma = wp_get_list_item_separator(); + $requires = sprintf( + /* translators: %s: List of dependency names. */ + __( '<strong>Requires:</strong> %s' ), + implode( $comma, $links ) + ); + + $notice = ''; + $error_message = ''; + if ( WP_Plugin_Dependencies::has_unmet_dependencies( $dependent ) ) { + if ( $is_active ) { + $error_message = __( 'This plugin is active but may not function correctly because required plugins are missing or inactive.' ); + } else { + $error_message = __( 'This plugin cannot be activated because required plugins are missing or inactive.' ); + } + $notice = wp_get_admin_notice( + $error_message, + array( + 'type' => 'error', + 'additional_classes' => array( 'inline', 'notice-alt' ), + ) + ); + } + + printf( + '<div class="requires"><p>%1$s</p><p>%2$s</p></div>', + $requires, + $notice + ); + } + + /** + * Returns a 'View details' like link for a dependency. + * + * @since 6.5.0 + * + * @param string $name The dependency's name. + * @param string $slug The dependency's slug. + * @return string A 'View details' link for the dependency. + */ + protected function get_dependency_view_details_link( $name, $slug ) { + $dependency_data = WP_Plugin_Dependencies::get_dependency_data( $slug ); + + if ( false === $dependency_data + || $name === $slug + || $name !== $dependency_data['name'] + || empty( $dependency_data['version'] ) + ) { + return $name; + } + + return $this->get_view_details_link( $name, $slug ); + } + + /** + * Returns a 'View details' link for the plugin. + * + * @since 6.5.0 + * + * @param string $name The plugin's name. + * @param string $slug The plugin's slug. + * @return string A 'View details' link for the plugin. + */ + protected function get_view_details_link( $name, $slug ) { + $url = add_query_arg( + array( + 'tab' => 'plugin-information', + 'plugin' => $slug, + 'TB_iframe' => 'true', + 'width' => '600', + 'height' => '550', + ), + network_admin_url( 'plugin-install.php' ) + ); + + $name_attr = esc_attr( $name ); + return sprintf( + "<a href='%s' class='thickbox open-plugin-details-modal' aria-label='%s' data-title='%s'>%s</a>", + esc_url( $url ), + /* translators: %s: Plugin name. */ + sprintf( __( 'More information about %s' ), $name_attr ), + $name_attr, + esc_html( $name ) + ); + } } diff --git a/wp-admin/includes/class-wp-privacy-policy-content.php b/wp-admin/includes/class-wp-privacy-policy-content.php index a64d043..e0775f7 100644 --- a/wp-admin/includes/class-wp-privacy-policy-content.php +++ b/wp-admin/includes/class-wp-privacy-policy-content.php @@ -466,7 +466,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Who we are' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Who we are' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -494,7 +494,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Comments' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Comments' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -507,7 +507,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Media' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Media' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -525,11 +525,11 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Cookies' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Cookies' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ - $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should list the cookies your web site uses, including those set by your plugins, social media, and analytics. We have provided the cookies which WordPress installs by default.' ) . '</p>'; + $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this subsection you should list the cookies your website uses, including those set by your plugins, social media, and analytics. We have provided the cookies which WordPress installs by default.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you leave a comment on our site you may opt-in to saving your name, email address and website in cookies. These are for your convenience so that you do not have to fill in your details again when you leave another comment. These cookies will last for one year.' ) . '</p>'; @@ -543,7 +543,7 @@ final class WP_Privacy_Policy_Content { if ( ! $description ) { /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Embedded content from other websites' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Embedded content from other websites' ) . '</h2>'; /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'Articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website.' ) . '</p>'; /* translators: Default privacy policy text. */ @@ -560,7 +560,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Who we share your data with' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Who we share your data with' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -573,11 +573,11 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'How long we retain your data' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'How long we retain your data' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ - $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain how long you retain personal data collected or processed by the web site. While it is your responsibility to come up with the schedule of how long you keep each dataset for and why you keep it, that information does need to be listed here. For example, you may want to say that you keep contact form entries for six months, analytics records for a year, and customer purchase records for ten years.' ) . '</p>'; + $strings[] = '<p class="privacy-policy-tutorial">' . __( 'In this section you should explain how long you retain personal data collected or processed by the website. While it is your responsibility to come up with the schedule of how long you keep each dataset for and why you keep it, that information does need to be listed here. For example, you may want to say that you keep contact form entries for six months, analytics records for a year, and customer purchase records for ten years.' ) . '</p>'; } else { /* translators: Default privacy policy text. */ $strings[] = '<p>' . $suggested_text . __( 'If you leave a comment, the comment and its metadata are retained indefinitely. This is so we can recognize and approve any follow-up comments automatically instead of holding them in a moderation queue.' ) . '</p>'; @@ -586,7 +586,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'What rights you have over your data' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'What rights you have over your data' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -597,7 +597,7 @@ final class WP_Privacy_Policy_Content { } /* translators: Default privacy policy heading. */ - $strings[] = '<h2>' . __( 'Where your data is sent' ) . '</h2>'; + $strings[] = '<h2 class="wp-block-heading">' . __( 'Where your data is sent' ) . '</h2>'; if ( $description ) { /* translators: Privacy policy tutorial. */ @@ -641,14 +641,14 @@ final class WP_Privacy_Policy_Content { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What third parties we receive data from' ) . '</h2>'; /* translators: Privacy policy tutorial. */ - $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your web site receives data about users from third parties, including advertisers, this information must be included within the section of your privacy policy dealing with third party data.' ) . '</p>'; + $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your website receives data about users from third parties, including advertisers, this information must be included within the section of your privacy policy dealing with third party data.' ) . '</p>'; } if ( $description ) { /* translators: Default privacy policy heading. */ $strings[] = '<h2>' . __( 'What automated decision making and/or profiling we do with user data' ) . '</h2>'; /* translators: Privacy policy tutorial. */ - $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your web site provides a service which includes automated decision making - for example, allowing customers to apply for credit, or aggregating their data into an advertising profile - you must note that this is taking place, and include information about how that information is used, what decisions are made with that aggregated data, and what rights users have over decisions made without human intervention.' ) . '</p>'; + $strings[] = '<p class="privacy-policy-tutorial">' . __( 'If your website provides a service which includes automated decision making - for example, allowing customers to apply for credit, or aggregating their data into an advertising profile - you must note that this is taking place, and include information about how that information is used, what decisions are made with that aggregated data, and what rights users have over decisions made without human intervention.' ) . '</p>'; } if ( $description ) { @@ -662,11 +662,11 @@ final class WP_Privacy_Policy_Content { if ( $blocks ) { foreach ( $strings as $key => $string ) { if ( str_starts_with( $string, '<p>' ) ) { - $strings[ $key ] = '<!-- wp:paragraph -->' . $string . '<!-- /wp:paragraph -->'; + $strings[ $key ] = "<!-- wp:paragraph -->\n" . $string . "\n<!-- /wp:paragraph -->\n"; } - if ( str_starts_with( $string, '<h2>' ) ) { - $strings[ $key ] = '<!-- wp:heading -->' . $string . '<!-- /wp:heading -->'; + if ( str_starts_with( $string, '<h2 ' ) ) { + $strings[ $key ] = "<!-- wp:heading -->\n" . $string . "\n<!-- /wp:heading -->\n"; } } } diff --git a/wp-admin/includes/class-wp-screen.php b/wp-admin/includes/class-wp-screen.php index 739a182..67bceef 100644 --- a/wp-admin/includes/class-wp-screen.php +++ b/wp-admin/includes/class-wp-screen.php @@ -1279,7 +1279,7 @@ final class WP_Screen { <?php if ( $per_page_label ) : ?> <label for="<?php echo esc_attr( $option ); ?>"><?php echo $per_page_label; ?></label> <input type="number" step="1" min="1" max="999" class="screen-per-page" name="wp_screen_options[value]" - id="<?php echo esc_attr( $option ); ?>" maxlength="3" + id="<?php echo esc_attr( $option ); ?>" value="<?php echo esc_attr( $per_page ); ?>" /> <?php endif; ?> <input type="hidden" name="wp_screen_options[option]" value="<?php echo esc_attr( $option ); ?>" /> diff --git a/wp-admin/includes/class-wp-site-health.php b/wp-admin/includes/class-wp-site-health.php index b73e1e7..da6c81e 100644 --- a/wp-admin/includes/class-wp-site-health.php +++ b/wp-admin/includes/class-wp-site-health.php @@ -17,7 +17,7 @@ class WP_Site_Health { public $is_mariadb = false; private $mysql_server_version = ''; private $mysql_required_version = '5.5'; - private $mysql_recommended_version = '5.7'; + private $mysql_recommended_version = '8.0'; private $mariadb_recommended_version = '10.4'; public $php_memory_limit; @@ -1288,13 +1288,9 @@ class WP_Site_Health { * * @since 5.2.0 * - * @global wpdb $wpdb WordPress database abstraction object. - * * @return array The test results. */ public function get_test_utf8mb4_support() { - global $wpdb; - if ( ! $this->mysql_server_version ) { $this->prepare_sql_data(); } diff --git a/wp-admin/includes/class-wp-site-icon.php b/wp-admin/includes/class-wp-site-icon.php index ff41771..d14ead3 100644 --- a/wp-admin/includes/class-wp-site-icon.php +++ b/wp-admin/includes/class-wp-site-icon.php @@ -78,12 +78,15 @@ class WP_Site_Icon { * Creates an attachment 'object'. * * @since 4.3.0 + * @deprecated 6.5.0 * * @param string $cropped Cropped image URL. * @param int $parent_attachment_id Attachment ID of parent image. * @return array An array with attachment object data. */ public function create_attachment_object( $cropped, $parent_attachment_id ) { + _deprecated_function( __METHOD__, '6.5.0', 'wp_copy_parent_attachment_properties()' ); + $parent = get_post( $parent_attachment_id ); $parent_url = wp_get_attachment_url( $parent->ID ); $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); diff --git a/wp-admin/includes/class-wp-theme-install-list-table.php b/wp-admin/includes/class-wp-theme-install-list-table.php index 318d8d8..945fb6e 100644 --- a/wp-admin/includes/class-wp-theme-install-list-table.php +++ b/wp-admin/includes/class-wp-theme-install-list-table.php @@ -333,7 +333,7 @@ class WP_Theme_Install_List_Table extends WP_Themes_List_Table { esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ), /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Install %s', 'theme' ), $name ) ), - __( 'Install Now' ) + _x( 'Install Now', 'theme' ) ); break; } diff --git a/wp-admin/includes/class-wp-themes-list-table.php b/wp-admin/includes/class-wp-themes-list-table.php index 8d385f9..fce3620 100644 --- a/wp-admin/includes/class-wp-themes-list-table.php +++ b/wp-admin/includes/class-wp-themes-list-table.php @@ -212,7 +212,7 @@ class WP_Themes_List_Table extends WP_List_Table { $activate_link, /* translators: %s: Theme name. */ esc_attr( sprintf( _x( 'Activate “%s”', 'theme' ), $title ) ), - __( 'Activate' ) + _x( 'Activate', 'theme' ) ); if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { diff --git a/wp-admin/includes/class-wp-upgrader-skin.php b/wp-admin/includes/class-wp-upgrader-skin.php index 598724f..83b4ba4 100644 --- a/wp-admin/includes/class-wp-upgrader-skin.php +++ b/wp-admin/includes/class-wp-upgrader-skin.php @@ -240,7 +240,14 @@ class WP_Upgrader_Skin { if ( defined( 'IFRAME_REQUEST' ) ) { echo '<script type="text/javascript"> if ( window.postMessage && JSON ) { - window.parent.postMessage( JSON.stringify( { action: "decrementUpdateCount", upgradeType: "' . $type . '" } ), window.location.protocol + "//" + window.location.hostname ); + window.parent.postMessage( + JSON.stringify( { + action: "decrementUpdateCount", + upgradeType: "' . $type . '" + } ), + window.location.protocol + "//" + window.location.hostname + + ( "" !== window.location.port ? ":" + window.location.port : "" ) + ); } </script>'; } else { diff --git a/wp-admin/includes/class-wp-users-list-table.php b/wp-admin/includes/class-wp-users-list-table.php index ecb8eb4..8dfe3ce 100644 --- a/wp-admin/includes/class-wp-users-list-table.php +++ b/wp-admin/includes/class-wp-users-list-table.php @@ -163,7 +163,7 @@ class WP_Users_List_Table extends WP_List_Table { * with this table. * * Provides a list of roles and user count for that role for easy - * Filtersing of the user table. + * filtering of the user table. * * @since 3.1.0 * diff --git a/wp-admin/includes/dashboard.php b/wp-admin/includes/dashboard.php index 5b50423..2aeaa24 100644 --- a/wp-admin/includes/dashboard.php +++ b/wp-admin/includes/dashboard.php @@ -1088,7 +1088,11 @@ function wp_dashboard_recent_comments( $total_items = 5 ) { } foreach ( $possible as $comment ) { - if ( ! current_user_can( 'read_post', $comment->comment_post_ID ) ) { + if ( ! current_user_can( 'edit_post', $comment->comment_post_ID ) + && ( post_password_required( $comment->comment_post_ID ) + || ! current_user_can( 'read_post', $comment->comment_post_ID ) ) + ) { + // The user has no access to the post and thus cannot see the comments. continue; } @@ -1109,16 +1113,7 @@ function wp_dashboard_recent_comments( $total_items = 5 ) { echo '<ul id="the-comment-list" data-wp-lists="list:comment">'; foreach ( $comments as $comment ) { - $comment_post = get_post( $comment->comment_post_ID ); - if ( - current_user_can( 'edit_post', $comment->comment_post_ID ) || - ( - empty( $comment_post->post_password ) && - current_user_can( 'read_post', $comment->comment_post_ID ) - ) - ) { - _wp_dashboard_recent_comments_row( $comment ); - } + _wp_dashboard_recent_comments_row( $comment ); } echo '</ul>'; @@ -1577,7 +1572,11 @@ function wp_dashboard_primary() { * * @param string $link The widget's secondary link URL. */ - 'link' => apply_filters( 'dashboard_secondary_link', __( 'https://planet.wordpress.org/' ) ), + 'link' => apply_filters( + 'dashboard_secondary_link', + /* translators: Link to the Planet website of the locale. */ + __( 'https://planet.wordpress.org/' ) + ), /** * Filters the secondary feed URL for the 'WordPress Events and News' dashboard widget. @@ -1586,7 +1585,11 @@ function wp_dashboard_primary() { * * @param string $url The widget's secondary feed URL. */ - 'url' => apply_filters( 'dashboard_secondary_feed', __( 'https://planet.wordpress.org/feed/' ) ), + 'url' => apply_filters( + 'dashboard_secondary_feed', + /* translators: Link to the Planet feed of the locale. */ + __( 'https://planet.wordpress.org/feed/' ) + ), /** * Filters the secondary link title for the 'WordPress Events and News' dashboard widget. diff --git a/wp-admin/includes/deprecated.php b/wp-admin/includes/deprecated.php index d588ad4..f7805b4 100644 --- a/wp-admin/includes/deprecated.php +++ b/wp-admin/includes/deprecated.php @@ -1152,7 +1152,7 @@ function wp_nav_menu_locations_meta_box() { /** * This was once used to kick-off the Core Updater. * - * Deprecated in favor of instantating a Core_Upgrader instance directly, + * Deprecated in favor of instantiating a Core_Upgrader instance directly, * and calling the 'upgrade' method. * * @since 2.7.0 @@ -1174,7 +1174,7 @@ function wp_update_core($current, $feedback = '') { /** * This was once used to kick-off the Plugin Updater. * - * Deprecated in favor of instantating a Plugin_Upgrader instance directly, + * Deprecated in favor of instantiating a Plugin_Upgrader instance directly, * and calling the 'upgrade' method. * Unused since 2.8.0. * diff --git a/wp-admin/includes/export.php b/wp-admin/includes/export.php index 9610ac8..d05f98f 100644 --- a/wp-admin/includes/export.php +++ b/wp-admin/includes/export.php @@ -144,6 +144,52 @@ function export_wp( $args = array() ) { // Grab a snapshot of post IDs, just in case it changes during the export. $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" ); + // Get IDs for the attachments of each post, unless all content is already being exported. + if ( ! in_array( $args['content'], array( 'all', 'attachment' ), true ) ) { + // Array to hold all additional IDs (attachments and thumbnails). + $additional_ids = array(); + + // Create a copy of the post IDs array to avoid modifying the original array. + $processing_ids = $post_ids; + + while ( $next_posts = array_splice( $processing_ids, 0, 20 ) ) { + $posts_in = array_map( 'absint', $next_posts ); + $placeholders = array_fill( 0, count( $posts_in ), '%d' ); + + // Create a string for the placeholders. + $in_placeholder = implode( ',', $placeholders ); + + // Prepare the SQL statement for attachment ids. + $attachment_ids = $wpdb->get_col( + $wpdb->prepare( + " + SELECT ID + FROM $wpdb->posts + WHERE post_parent IN ($in_placeholder) AND post_type = 'attachment' + ", + $posts_in + ) + ); + + $thumbnails_ids = $wpdb->get_col( + $wpdb->prepare( + " + SELECT meta_value + FROM $wpdb->postmeta + WHERE $wpdb->postmeta.post_id IN ($in_placeholder) + AND $wpdb->postmeta.meta_key = '_thumbnail_id' + ", + $posts_in + ) + ); + + $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 ) ); + } + /* * Get the requested terms ready, empty unless posts filtered by category * or all content. diff --git a/wp-admin/includes/file.php b/wp-admin/includes/file.php index 600ddc2..5832569 100644 --- a/wp-admin/includes/file.php +++ b/wp-admin/includes/file.php @@ -656,7 +656,7 @@ function wp_edit_theme_plugin_file( $args ) { /** * Returns a filename of a temporary unique file. * - * Please note that the calling function must unlink() this itself. + * Please note that the calling function must delete or move the file. * * The filename is based off the passed parameter or defaults to the current unix timestamp, * while the directory can either be passed as well, or by leaving it blank, default to a writable @@ -1139,7 +1139,7 @@ function wp_handle_sideload( &$file, $overrides = false, $time = null ) { /** * Downloads a URL to a local temporary file using the WordPress HTTP API. * - * Please note that the calling function must unlink() the file. + * Please note that the calling function must delete or move the file. * * @since 2.5.0 * @since 5.2.0 Signature Verification with SoftFail was added. @@ -1153,7 +1153,7 @@ function wp_handle_sideload( &$file, $overrides = false, $time = null ) { * @return string|WP_Error Filename on success, WP_Error on failure. */ function download_url( $url, $timeout = 300, $signature_verification = false ) { - // WARNING: The file is not automatically deleted, the script must unlink() the file. + // WARNING: The file is not automatically deleted, the script must delete or move the file. if ( ! $url ) { return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) ); } @@ -1564,6 +1564,37 @@ function wp_trusted_keys() { } /** + * Determines whether the given file is a valid ZIP file. + * + * This function does not test to ensure that a file exists. Non-existent files + * are not valid ZIPs, so those will also return false. + * + * @since 6.4.4 + * + * @param string $file Full path to the ZIP file. + * @return bool Whether the file is a valid ZIP file. + */ +function wp_zip_file_is_valid( $file ) { + /** This filter is documented in wp-admin/includes/file.php */ + if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) { + $archive = new ZipArchive(); + $archive_is_valid = $archive->open( $file, ZipArchive::CHECKCONS ); + if ( true === $archive_is_valid ) { + $archive->close(); + return true; + } + } + + // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file. + require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; + + $archive = new PclZip( $file ); + $archive_is_valid = is_array( $archive->properties() ); + + return $archive_is_valid; +} + +/** * Unzips a specified ZIP file to a location on the filesystem via the WordPress * Filesystem Abstraction. * diff --git a/wp-admin/includes/image-edit.php b/wp-admin/includes/image-edit.php index 739b09f..2d150e6 100644 --- a/wp-admin/includes/image-edit.php +++ b/wp-admin/includes/image-edit.php @@ -390,6 +390,12 @@ function wp_stream_image( $image, $mime_type, $attachment_id ) { return imagewebp( $image, null, 90 ); } return false; + case 'image/avif': + if ( function_exists( 'imageavif' ) ) { + header( 'Content-Type: image/avif' ); + return imageavif( $image, null, 90 ); + } + return false; default: return false; } @@ -494,6 +500,11 @@ function wp_save_image_file( $filename, $image, $mime_type, $post_id ) { return imagewebp( $image, $filename ); } return false; + case 'image/avif': + if ( function_exists( 'imageavif' ) ) { + return imageavif( $image, $filename ); + } + return false; default: return false; } diff --git a/wp-admin/includes/image.php b/wp-admin/includes/image.php index 2bdcc50..69f58d5 100644 --- a/wp-admin/includes/image.php +++ b/wp-admin/includes/image.php @@ -483,6 +483,62 @@ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { } /** + * Copy parent attachment properties to newly cropped image. + * + * @since 6.5.0 + * + * @param string $cropped Path to the cropped image file. + * @param int $parent_attachment_id Parent file Attachment ID. + * @param string $context Control calling the function. + * @return array Properties of attachment. + */ +function wp_copy_parent_attachment_properties( $cropped, $parent_attachment_id, $context = '' ) { + $parent = get_post( $parent_attachment_id ); + $parent_url = wp_get_attachment_url( $parent->ID ); + $parent_basename = wp_basename( $parent_url ); + $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); + + $size = wp_getimagesize( $cropped ); + $image_type = $size ? $size['mime'] : 'image/jpeg'; + + $sanitized_post_title = sanitize_file_name( $parent->post_title ); + $use_original_title = ( + ( '' !== trim( $parent->post_title ) ) && + /* + * Check if the original image has a title other than the "filename" default, + * meaning the image had a title when originally uploaded or its title was edited. + */ + ( $parent_basename !== $sanitized_post_title ) && + ( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title ) + ); + $use_original_description = ( '' !== trim( $parent->post_content ) ); + + $attachment = array( + 'post_title' => $use_original_title ? $parent->post_title : wp_basename( $cropped ), + 'post_content' => $use_original_description ? $parent->post_content : $url, + 'post_mime_type' => $image_type, + 'guid' => $url, + 'context' => $context, + ); + + // Copy the image caption attribute (post_excerpt field) from the original image. + if ( '' !== trim( $parent->post_excerpt ) ) { + $attachment['post_excerpt'] = $parent->post_excerpt; + } + + // Copy the image alt text attribute from the original image. + if ( '' !== trim( $parent->_wp_attachment_image_alt ) ) { + $attachment['meta_input'] = array( + '_wp_attachment_image_alt' => wp_slash( $parent->_wp_attachment_image_alt ), + ); + } + + $attachment['post_parent'] = $parent_attachment_id; + + return $attachment; +} + +/** * Generates attachment meta data and create image sub-sizes for images. * * @since 2.1.0 @@ -863,22 +919,51 @@ function wp_read_image_metadata( $file ) { $exif = array(); } + $exif_description = ''; + $exif_usercomment = ''; if ( ! empty( $exif['ImageDescription'] ) ) { + $exif_description = trim( $exif['ImageDescription'] ); + } + + if ( ! empty( $exif['COMPUTED']['UserComment'] ) ) { + $exif_usercomment = trim( $exif['COMPUTED']['UserComment'] ); + } + + if ( $exif_description ) { mbstring_binary_safe_encoding(); - $description_length = strlen( $exif['ImageDescription'] ); + $description_length = strlen( $exif_description ); reset_mbstring_encoding(); - if ( empty( $meta['title'] ) && $description_length < 80 ) { // Assume the title is stored in ImageDescription. - $meta['title'] = trim( $exif['ImageDescription'] ); + $meta['title'] = $exif_description; } - if ( empty( $meta['caption'] ) && ! empty( $exif['COMPUTED']['UserComment'] ) ) { - $meta['caption'] = trim( $exif['COMPUTED']['UserComment'] ); + // If both user comments and description are present. + if ( empty( $meta['caption'] ) && $exif_description && $exif_usercomment ) { + if ( ! empty( $meta['title'] ) && $exif_description === $meta['title'] ) { + $caption = $exif_usercomment; + } else { + if ( $exif_description === $exif_usercomment ) { + $caption = $exif_description; + } else { + $caption = trim( $exif_description . ' ' . $exif_usercomment ); + } + } + $meta['caption'] = $caption; + } + + if ( empty( $meta['caption'] ) && $exif_usercomment ) { + $meta['caption'] = $exif_usercomment; } if ( empty( $meta['caption'] ) ) { - $meta['caption'] = trim( $exif['ImageDescription'] ); + $meta['caption'] = $exif_description; + } + } elseif ( empty( $meta['caption'] ) && $exif_usercomment ) { + $meta['caption'] = $exif_usercomment; + $description_length = strlen( $exif_usercomment ); + if ( empty( $meta['title'] ) && $description_length < 80 ) { + $meta['title'] = trim( $exif_usercomment ); } } elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) { $meta['caption'] = trim( $exif['Comments'] ); @@ -977,7 +1062,7 @@ function file_is_valid_image( $path ) { * @return bool True if suitable, false if not suitable. */ function file_is_displayable_image( $path ) { - $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); + $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP, IMAGETYPE_AVIF ); $info = wp_getimagesize( $path ); if ( empty( $info ) ) { diff --git a/wp-admin/includes/media.php b/wp-admin/includes/media.php index e7b4c10..3de25dc 100644 --- a/wp-admin/includes/media.php +++ b/wp-admin/includes/media.php @@ -527,12 +527,14 @@ function media_handle_sideload( $file_array, $post_id = 0, $desc = null, $post_d * @since 5.3.0 Formalized the existing and already documented `...$args` parameter * by adding it to the function signature. * - * @global int $body_id + * @global string $body_id * * @param callable $content_func Function that outputs the content. * @param mixed ...$args Optional additional parameters to pass to the callback function when it's called. */ function wp_iframe( $content_func, ...$args ) { + global $body_id; + _wp_admin_html_begin(); ?> <title><?php bloginfo( 'name' ); ?> › <?php _e( 'Uploads' ); ?> — <?php _e( 'WordPress' ); ?></title> @@ -603,8 +605,8 @@ function wp_iframe( $content_func, ...$args ) { $body_id_attr = ''; - if ( isset( $GLOBALS['body_id'] ) ) { - $body_id_attr = ' id="' . $GLOBALS['body_id'] . '"'; + if ( isset( $body_id ) ) { + $body_id_attr = ' id="' . $body_id . '"'; } ?> @@ -2196,6 +2198,11 @@ function media_upload_form( $errors = null ) { $plupload_init['webp_upload_error'] = true; } + // Check if AVIF images can be edited. + if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { + $plupload_init['avif_upload_error'] = true; + } + /** * Filters the default Plupload settings. * @@ -2825,7 +2832,7 @@ function media_upload_library_form( $errors ) { 'format' => '', 'prev_text' => __( '«' ), 'next_text' => __( '»' ), - 'total' => ceil( $wp_query->found_posts / 10 ), + 'total' => (int) ceil( $wp_query->found_posts / 10 ), 'current' => $q['paged'], ) ); diff --git a/wp-admin/includes/menu.php b/wp-admin/includes/menu.php index da1b2eb..3cf4a5f 100644 --- a/wp-admin/includes/menu.php +++ b/wp-admin/includes/menu.php @@ -13,8 +13,8 @@ if ( is_network_admin() ) { * * The hook fires before menus and sub-menus are removed based on user privileges. * - * @private * @since 3.1.0 + * @access private */ do_action( '_network_admin_menu' ); } elseif ( is_user_admin() ) { @@ -24,8 +24,8 @@ if ( is_network_admin() ) { * * The hook fires before menus and sub-menus are removed based on user privileges. * - * @private * @since 3.1.0 + * @access private */ do_action( '_user_admin_menu' ); } else { @@ -35,8 +35,8 @@ if ( is_network_admin() ) { * * The hook fires before menus and sub-menus are removed based on user privileges. * - * @private * @since 2.2.0 + * @access private */ do_action( '_admin_menu' ); } diff --git a/wp-admin/includes/meta-boxes.php b/wp-admin/includes/meta-boxes.php index 5228076..387910e 100644 --- a/wp-admin/includes/meta-boxes.php +++ b/wp-admin/includes/meta-boxes.php @@ -434,7 +434,7 @@ function attachment_submit_meta_box( $post ) { <span id="timestamp"> <?php $uploaded_on = sprintf( - /* translators: Publish box date string. 1: Date, 2: Time. See https://www.php.net/manual/datetime.format.php */ + /* translators: Publish box date string. 1: Date, 2: Time. */ __( '%1$s at %2$s' ), /* translators: Publish box date format, see https://www.php.net/manual/datetime.format.php */ date_i18n( _x( 'M j, Y', 'publish box date format' ), strtotime( $post->post_date ) ), diff --git a/wp-admin/includes/misc.php b/wp-admin/includes/misc.php index 0902820..f950821 100644 --- a/wp-admin/includes/misc.php +++ b/wp-admin/includes/misc.php @@ -39,11 +39,12 @@ function got_mod_rewrite() { * @since 3.7.0 * * @global bool $is_nginx + * @global bool $is_caddy * * @return bool Whether the server supports URL rewriting. */ function got_url_rewrite() { - $got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() ); + $got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || $GLOBALS['is_caddy'] || iis7_supports_permalinks() ); /** * Filters whether URL rewriting is available. @@ -1038,17 +1039,15 @@ function admin_color_scheme_picker( $user_id ) { <input type="hidden" class="css_url" value="<?php echo esc_url( $color_info->url ); ?>" /> <input type="hidden" class="icon_colors" value="<?php echo esc_attr( wp_json_encode( array( 'icons' => $color_info->icon_colors ) ) ); ?>" /> <label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label> - <table class="color-palette"> - <tr> - <?php - foreach ( $color_info->colors as $html_color ) { - ?> - <td style="background-color: <?php echo esc_attr( $html_color ); ?>"> </td> - <?php - } + <div class="color-palette"> + <?php + foreach ( $color_info->colors as $html_color ) { ?> - </tr> - </table> + <div class="color-palette-shade" style="background-color: <?php echo esc_attr( $html_color ); ?>"> </div> + <?php + } + ?> + </div> </div> <?php @@ -1398,6 +1397,15 @@ function wp_admin_canonical_url() { // Ensure we're using an absolute URL. $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); $filtered_url = remove_query_arg( $removable_query_args, $current_url ); + + /** + * Filters the admin canonical url value. + * + * @since 6.5.0 + * + * @param string $filtered_url The admin canonical url value. + */ + $filtered_url = apply_filters( 'wp_admin_canonical_url', $filtered_url ); ?> <link id="wp-admin-canonical" rel="canonical" href="<?php echo esc_url( $filtered_url ); ?>" /> <script> @@ -1499,11 +1507,11 @@ All at ###SITENAME### * Filters the text of the email sent when a change of site admin email address is attempted. * * The following strings have a special meaning and will get replaced dynamically: - * ###USERNAME### The current user's username. - * ###ADMIN_URL### The link to click on to confirm the email change. - * ###EMAIL### The proposed new site admin email address. - * ###SITENAME### The name of the site. - * ###SITEURL### The URL to the site. + * - ###USERNAME### The current user's username. + * - ###ADMIN_URL### The link to click on to confirm the email change. + * - ###EMAIL### The proposed new site admin email address. + * - ###SITENAME### The name of the site. + * - ###SITEURL### The URL to the site. * * @since MU (3.0.0) * @since 4.9.0 This filter is no longer Multisite specific. @@ -1531,16 +1539,23 @@ All at ###SITENAME### $site_title = parse_url( home_url(), PHP_URL_HOST ); } - wp_mail( - $value, - sprintf( - /* translators: New admin email address notification email subject. %s: Site title. */ - __( '[%s] New Admin Email Address' ), - $site_title - ), - $content + $subject = sprintf( + /* translators: New admin email address notification email subject. %s: Site title. */ + __( '[%s] New Admin Email Address' ), + $site_title ); + /** + * Filters the subject of the email sent when a change of site admin email address is attempted. + * + * @since 6.5.0 + * + * @param string $subject Subject of the email. + */ + $subject = apply_filters( 'new_admin_email_subject', $subject ); + + wp_mail( $value, $subject, $content ); + if ( $switched_locale ) { restore_previous_locale(); } diff --git a/wp-admin/includes/ms.php b/wp-admin/includes/ms.php index 0d04666..02ddf94 100644 --- a/wp-admin/includes/ms.php +++ b/wp-admin/includes/ms.php @@ -305,7 +305,9 @@ function upload_space_setting( $id ) { <tr> <th><label for="blog-upload-space-number"><?php _e( 'Site Upload Space Quota' ); ?></label></th> <td> - <input type="number" step="1" min="0" style="width: 100px" name="option[blog_upload_space]" id="blog-upload-space-number" aria-describedby="blog-upload-space-desc" value="<?php echo $quota; ?>" /> + <input type="number" step="1" min="0" style="width: 100px" + name="option[blog_upload_space]" id="blog-upload-space-number" + aria-describedby="blog-upload-space-desc" value="<?php echo esc_attr( $quota ); ?>" /> <span id="blog-upload-space-desc"><span class="screen-reader-text"> <?php /* translators: Hidden accessibility text. */ diff --git a/wp-admin/includes/nav-menu.php b/wp-admin/includes/nav-menu.php index 704f031..8f18057 100644 --- a/wp-admin/includes/nav-menu.php +++ b/wp-admin/includes/nav-menu.php @@ -874,7 +874,7 @@ function wp_nav_menu_item_taxonomy_meta_box( $data_object, $box ) { return; } - $num_pages = ceil( + $num_pages = (int) ceil( wp_count_terms( array_merge( $args, diff --git a/wp-admin/includes/options.php b/wp-admin/includes/options.php index 816313c..2ede58c 100644 --- a/wp-admin/includes/options.php +++ b/wp-admin/includes/options.php @@ -36,6 +36,7 @@ function options_general_add_js() { <script type="text/javascript"> jQuery( function($) { var $siteName = $( '#wp-admin-bar-site-name' ).children( 'a' ).first(), + $siteIconPreview = $('#site-icon-preview-site-title'), homeURL = ( <?php echo wp_json_encode( get_home_url() ); ?> || '' ).replace( /^(https?:\/\/)?(www\.)?/, '' ); $( '#blogname' ).on( 'input', function() { @@ -47,6 +48,7 @@ function options_general_add_js() { } $siteName.text( title ); + $siteIconPreview.text( title ); }); $( 'input[name="date_format"]' ).on( 'click', function() { diff --git a/wp-admin/includes/plugin-install.php b/wp-admin/includes/plugin-install.php index 7662076..a3afbcb 100644 --- a/wp-admin/includes/plugin-install.php +++ b/wp-admin/includes/plugin-install.php @@ -361,7 +361,7 @@ function install_plugins_upload() { ?> </label> <input type="file" id="pluginzip" name="pluginzip" accept=".zip" /> - <?php submit_button( __( 'Install Now' ), '', 'install-plugin-submit', false ); ?> + <?php submit_button( _x( 'Install Now', 'plugin' ), '', 'install-plugin-submit', false ); ?> </form> </div> <?php @@ -884,43 +884,176 @@ function install_plugin_information() { echo "</div>\n"; // #plugin-information-scrollable echo "<div id='$tab-footer'>\n"; if ( ! empty( $api->download_link ) && ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) { - $status = install_plugin_install_status( $api ); + $button = wp_get_plugin_action_button( $api->name, $api, $compatible_php, $compatible_wp ); + $button = str_replace( 'class="', 'class="right ', $button ); + + if ( ! str_contains( $button, _x( 'Activate', 'plugin' ) ) ) { + $button = str_replace( 'class="', 'id="plugin_install_from_iframe" class="', $button ); + } + + echo wp_kses_post( $button ); + } + echo "</div>\n"; + + wp_print_request_filesystem_credentials_modal(); + wp_print_admin_notice_templates(); + + iframe_footer(); + exit; +} + +/** + * Gets the markup for the plugin install action button. + * + * @since 6.5.0 + * + * @param string $name Plugin name. + * @param array|object $data { + * An array or object of plugin data. Can be retrieved from the API. + * + * @type string $slug The plugin slug. + * @type string[] $requires_plugins An array of plugin dependency slugs. + * @type string $version The plugin's version string. Used when getting the install status. + * } + * @param bool $compatible_php The result of a PHP compatibility check. + * @param bool $compatible_wp The result of a WP compatibility check. + * @return string $button The markup for the dependency row button. + */ +function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible_wp ) { + $button = ''; + $data = (object) $data; + $status = install_plugin_install_status( $data ); + $requires_plugins = $data->requires_plugins ?? array(); + + // Determine the status of plugin dependencies. + $installed_plugins = get_plugins(); + $active_plugins = get_option( 'active_plugins', array() ); + $plugin_dependencies_count = count( $requires_plugins ); + $installed_plugin_dependencies_count = 0; + $active_plugin_dependencies_count = 0; + foreach ( $requires_plugins as $dependency ) { + foreach ( array_keys( $installed_plugins ) as $installed_plugin_file ) { + if ( str_contains( $installed_plugin_file, '/' ) && explode( '/', $installed_plugin_file )[0] === $dependency ) { + ++$installed_plugin_dependencies_count; + } + } + + foreach ( $active_plugins as $active_plugin_file ) { + if ( str_contains( $active_plugin_file, '/' ) && explode( '/', $active_plugin_file )[0] === $dependency ) { + ++$active_plugin_dependencies_count; + } + } + } + $all_plugin_dependencies_installed = $installed_plugin_dependencies_count === $plugin_dependencies_count; + $all_plugin_dependencies_active = $active_plugin_dependencies_count === $plugin_dependencies_count; + + sprintf( + '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>', + esc_attr( $data->slug ), + esc_url( $status['url'] ), + /* translators: %s: Plugin name and version. */ + esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ), + esc_attr( $name ), + _x( 'Install Now', 'plugin' ) + ); + + if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) { switch ( $status['status'] ) { case 'install': if ( $status['url'] ) { - if ( $compatible_php && $compatible_wp ) { - echo '<a data-slug="' . esc_attr( $api->slug ) . '" id="plugin_install_from_iframe" class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>'; + if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_installed && ! empty( $data->download_link ) ) { + $button = sprintf( + '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>', + esc_attr( $data->slug ), + esc_url( $status['url'] ), + /* translators: %s: Plugin name and version. */ + esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ), + esc_attr( $name ), + _x( 'Install Now', 'plugin' ) + ); } else { - printf( - '<button type="button" class="button button-primary button-disabled right" disabled="disabled">%s</button>', - _x( 'Cannot Install', 'plugin' ) + $button = sprintf( + '<button type="button" class="install-now button button-disabled" disabled="disabled">%s</button>', + _x( 'Install Now', 'plugin' ) ); } } break; + case 'update_available': if ( $status['url'] ) { - if ( $compatible_php ) { - echo '<a data-slug="' . esc_attr( $api->slug ) . '" data-plugin="' . esc_attr( $status['file'] ) . '" id="plugin_update_from_iframe" class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) . '</a>'; + if ( $compatible_php && $compatible_wp ) { + $button = sprintf( + '<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>', + esc_attr( $status['file'] ), + esc_attr( $data->slug ), + esc_url( $status['url'] ), + /* translators: %s: Plugin name and version. */ + esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ), + esc_attr( $name ), + _x( 'Update Now', 'plugin' ) + ); } else { - printf( - '<button type="button" class="button button-primary button-disabled right" disabled="disabled">%s</button>', - _x( 'Cannot Update', 'plugin' ) + $button = sprintf( + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', + _x( 'Update Now', 'plugin' ) ); } } break; - case 'newer_installed': - /* translators: %s: Plugin version. */ - echo '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed' ), esc_html( $status['version'] ) ) . '</a>'; - break; + case 'latest_installed': - echo '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>'; + case 'newer_installed': + if ( is_plugin_active( $status['file'] ) ) { + $button = sprintf( + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', + _x( 'Active', 'plugin' ) + ); + } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) { + if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_active ) { + $button_text = _x( 'Activate', 'plugin' ); + /* translators: %s: Plugin name. */ + $button_label = _x( 'Activate %s', 'plugin' ); + $activate_url = add_query_arg( + array( + '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), + 'action' => 'activate', + 'plugin' => $status['file'], + ), + network_admin_url( 'plugins.php' ) + ); + + if ( is_network_admin() ) { + $button_text = _x( 'Network Activate', 'plugin' ); + /* translators: %s: Plugin name. */ + $button_label = _x( 'Network Activate %s', 'plugin' ); + $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url ); + } + + $button = sprintf( + '<a href="%1$s" data-name="%2$s" data-slug="%3$s" data-plugin="%4$s" class="button button-primary activate-now" aria-label="%5$s">%6$s</a>', + esc_url( $activate_url ), + esc_attr( $name ), + esc_attr( $data->slug ), + esc_attr( $status['file'] ), + esc_attr( sprintf( $button_label, $name ) ), + $button_text + ); + } else { + $button = sprintf( + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', + is_network_admin() ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' ) + ); + } + } else { + $button = sprintf( + '<button type="button" class="button button-disabled" disabled="disabled">%s</button>', + _x( 'Installed', 'plugin' ) + ); + } break; } - } - echo "</div>\n"; - iframe_footer(); - exit; + return $button; + } } diff --git a/wp-admin/includes/plugin.php b/wp-admin/includes/plugin.php index f55bbd8..bcae273 100644 --- a/wp-admin/includes/plugin.php +++ b/wp-admin/includes/plugin.php @@ -45,6 +45,7 @@ * @since 1.5.0 * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers. * @since 5.8.0 Added support for `Update URI` header. + * @since 6.5.0 Added support for `Requires Plugins` header. * * @param string $plugin_file Absolute path to the main plugin file. * @param bool $markup Optional. If the returned data should have HTML markup applied. @@ -53,39 +54,41 @@ * @return array { * Plugin data. Values will be empty if not supplied by the plugin. * - * @type string $Name Name of the plugin. Should be unique. - * @type string $PluginURI Plugin URI. - * @type string $Version Plugin version. - * @type string $Description Plugin description. - * @type string $Author Plugin author's name. - * @type string $AuthorURI Plugin author's website address (if set). - * @type string $TextDomain Plugin textdomain. - * @type string $DomainPath Plugin's relative directory path to .mo files. - * @type bool $Network Whether the plugin can only be activated network-wide. - * @type string $RequiresWP Minimum required version of WordPress. - * @type string $RequiresPHP Minimum required version of PHP. - * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. - * @type string $Title Title of the plugin and link to the plugin's site (if set). - * @type string $AuthorName Plugin author's name. + * @type string $Name Name of the plugin. Should be unique. + * @type string $PluginURI Plugin URI. + * @type string $Version Plugin version. + * @type string $Description Plugin description. + * @type string $Author Plugin author's name. + * @type string $AuthorURI Plugin author's website address (if set). + * @type string $TextDomain Plugin textdomain. + * @type string $DomainPath Plugin's relative directory path to .mo files. + * @type bool $Network Whether the plugin can only be activated network-wide. + * @type string $RequiresWP Minimum required version of WordPress. + * @type string $RequiresPHP Minimum required version of PHP. + * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. + * @type string $RequiresPlugins Comma separated list of dot org plugin slugs. + * @type string $Title Title of the plugin and link to the plugin's site (if set). + * @type string $AuthorName Plugin author's name. * } */ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { $default_headers = array( - 'Name' => 'Plugin Name', - 'PluginURI' => 'Plugin URI', - 'Version' => 'Version', - 'Description' => 'Description', - 'Author' => 'Author', - 'AuthorURI' => 'Author URI', - 'TextDomain' => 'Text Domain', - 'DomainPath' => 'Domain Path', - 'Network' => 'Network', - 'RequiresWP' => 'Requires at least', - 'RequiresPHP' => 'Requires PHP', - 'UpdateURI' => 'Update URI', + 'Name' => 'Plugin Name', + 'PluginURI' => 'Plugin URI', + 'Version' => 'Version', + 'Description' => 'Description', + 'Author' => 'Author', + 'AuthorURI' => 'Author URI', + 'TextDomain' => 'Text Domain', + 'DomainPath' => 'Domain Path', + 'Network' => 'Network', + 'RequiresWP' => 'Requires at least', + 'RequiresPHP' => 'Requires PHP', + 'UpdateURI' => 'Update URI', + 'RequiresPlugins' => 'Requires Plugins', // Site Wide Only is deprecated in favor of Network. - '_sitewide' => 'Site Wide Only', + '_sitewide' => 'Site Wide Only', ); $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' ); @@ -478,14 +481,23 @@ function get_dropins() { } /** - * Returns drop-ins that WordPress uses. + * Returns drop-in plugins that WordPress uses. * * Includes Multisite drop-ins only when is_multisite() * * @since 3.0.0 - * @return array[] Key is file name. The value is an array, with the first value the - * purpose of the drop-in and the second value the name of the constant that must be - * true for the drop-in to be used, or true if no constant is required. + * + * @return array[] { + * Key is file name. The value is an array of data about the drop-in. + * + * @type array ...$0 { + * Data about the drop-in. + * + * @type string $0 The purpose of the drop-in. + * @type string|true $1 Name of the constant that must be true for the drop-in + * to be used, or true if no constant is required. + * } + * } */ function _get_dropins() { $dropins = array( @@ -1009,6 +1021,7 @@ function delete_plugins( $plugins, $deprecated = '' ) { foreach ( $translations as $translation => $data ) { $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' ); $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' ); + $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.l10n.php' ); $json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' ); if ( $json_translation_files ) { @@ -1113,13 +1126,14 @@ function validate_plugin( $plugin ) { /** * Validates the plugin requirements for WordPress version and PHP version. * - * Uses the information from `Requires at least` and `Requires PHP` headers + * Uses the information from `Requires at least`, `Requires PHP` and `Requires Plugins` headers * defined in the plugin's main PHP file. * * @since 5.2.0 * @since 5.3.0 Added support for reading the headers from the plugin's * main PHP file, with `readme.txt` as a fallback. * @since 5.8.0 Removed support for using `readme.txt` as a fallback. + * @since 6.5.0 Added support for the 'Requires Plugins' header. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return true|WP_Error True if requirements are met, WP_Error on failure. @@ -1128,8 +1142,9 @@ function validate_plugin_requirements( $plugin ) { $plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); $requirements = array( - 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '', - 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', + 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '', + 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', + 'requires_plugins' => ! empty( $plugin_headers['RequiresPlugins'] ) ? $plugin_headers['RequiresPlugins'] : '', ); $compatible_wp = is_wp_version_compatible( $requirements['requires'] ); @@ -1184,6 +1199,62 @@ function validate_plugin_requirements( $plugin ) { ); } + WP_Plugin_Dependencies::initialize(); + + if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) { + $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $plugin ); + $unmet_dependencies = array(); + $unmet_dependency_names = array(); + + foreach ( $dependency_names as $dependency => $dependency_name ) { + $dependency_file = WP_Plugin_Dependencies::get_dependency_filepath( $dependency ); + + if ( false === $dependency_file ) { + $unmet_dependencies['not_installed'][ $dependency ] = $dependency_name; + $unmet_dependency_names[] = $dependency_name; + } elseif ( is_plugin_inactive( $dependency_file ) ) { + $unmet_dependencies['inactive'][ $dependency ] = $dependency_name; + $unmet_dependency_names[] = $dependency_name; + } + } + + $error_message = sprintf( + /* translators: 1: Plugin name, 2: Number of plugins, 3: A comma-separated list of plugin names. */ + _n( + '<strong>Error:</strong> %1$s requires %2$d plugin to be installed and activated: %3$s.', + '<strong>Error:</strong> %1$s requires %2$d plugins to be installed and activated: %3$s.', + count( $unmet_dependency_names ) + ), + $plugin_headers['Name'], + count( $unmet_dependency_names ), + implode( wp_get_list_item_separator(), $unmet_dependency_names ) + ); + + if ( is_multisite() ) { + if ( current_user_can( 'manage_network_plugins' ) ) { + $error_message .= ' ' . sprintf( + /* translators: %s: Link to the plugins page. */ + __( '<a href="%s">Manage plugins</a>.' ), + esc_url( network_admin_url( 'plugins.php' ) ) + ); + } else { + $error_message .= ' ' . __( 'Please contact your network administrator.' ); + } + } else { + $error_message .= ' ' . sprintf( + /* translators: %s: Link to the plugins page. */ + __( '<a href="%s">Manage plugins</a>.' ), + esc_url( admin_url( 'plugins.php' ) ) + ); + } + + return new WP_Error( + 'plugin_missing_dependencies', + "<p>{$error_message}</p>", + $unmet_dependencies + ); + } + return true; } @@ -2386,6 +2457,8 @@ function wp_add_privacy_policy_content( $plugin_name, $policy_text ) { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_plugins + * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return bool True, if in the list of paused plugins. False, if not in the list. */ @@ -2408,6 +2481,8 @@ function is_plugin_paused( $plugin ) { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_plugins + * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return array|false Array of error information as returned by `error_get_last()`, * or false if none was recorded. @@ -2482,7 +2557,8 @@ function resume_plugin( $plugin, $redirect = '' ) { * * @since 5.2.0 * - * @global string $pagenow The filename of the current screen. + * @global string $pagenow The filename of the current screen. + * @global WP_Paused_Extensions_Storage $_paused_plugins */ function paused_plugins_notice() { if ( 'plugins.php' === $GLOBALS['pagenow'] ) { diff --git a/wp-admin/includes/post.php b/wp-admin/includes/post.php index b9986d1..a313324 100644 --- a/wp-admin/includes/post.php +++ b/wp-admin/includes/post.php @@ -452,7 +452,7 @@ function edit_post( $post_data = null ) { $success = wp_update_post( $translated ); - // If the save failed, see if we can sanity check the main fields and try again. + // If the save failed, see if we can confidence check the main fields and try again. if ( ! $success && is_callable( array( $wpdb, 'strip_invalid_text_for_column' ) ) ) { $fields = array( 'post_title', 'post_content', 'post_excerpt' ); @@ -649,8 +649,21 @@ function bulk_edit_posts( $post_data = null ) { } if ( isset( $new_cats ) && in_array( 'category', $tax_names, true ) ) { - $cats = (array) wp_get_post_categories( $post_id ); - $post_data['post_category'] = array_unique( array_merge( $cats, $new_cats ) ); + $cats = (array) wp_get_post_categories( $post_id ); + + if ( + isset( $post_data['indeterminate_post_category'] ) + && is_array( $post_data['indeterminate_post_category'] ) + ) { + $indeterminate_post_category = $post_data['indeterminate_post_category']; + } else { + $indeterminate_post_category = array(); + } + + $indeterminate_cats = array_intersect( $cats, $indeterminate_post_category ); + $determinate_cats = array_diff( $new_cats, $indeterminate_post_category ); + $post_data['post_category'] = array_unique( array_merge( $indeterminate_cats, $determinate_cats ) ); + unset( $post_data['tax_input']['category'] ); } @@ -2303,6 +2316,7 @@ function get_block_editor_server_block_settings() { 'keywords' => 'keywords', 'example' => 'example', 'variations' => 'variations', + 'allowed_blocks' => 'allowedBlocks', ); foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) { diff --git a/wp-admin/includes/revision.php b/wp-admin/includes/revision.php index 8ed45fd..a0f2c0e 100644 --- a/wp-admin/includes/revision.php +++ b/wp-admin/includes/revision.php @@ -85,7 +85,7 @@ function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) { * @param string $field The current revision field. * @param WP_Post $compare_from The revision post object to compare to or from. * @param string $context The context of whether the current revision is the old - * or the new one. Values are 'to' or 'from'. + * or the new one. Either 'to' or 'from'. */ $content_from = $compare_from ? apply_filters( "_wp_post_revision_field_{$field}", $compare_from->$field, $field, $compare_from, 'from' ) : ''; diff --git a/wp-admin/includes/schema.php b/wp-admin/includes/schema.php index 20648d7..63655cc 100644 --- a/wp-admin/includes/schema.php +++ b/wp-admin/includes/schema.php @@ -1250,6 +1250,7 @@ We hope you enjoy your new site. Thanks! 'png', 'gif', 'webp', + 'avif', // Video. 'mov', 'avi', diff --git a/wp-admin/includes/template.php b/wp-admin/includes/template.php index 1d4a8e8..90b375e 100644 --- a/wp-admin/includes/template.php +++ b/wp-admin/includes/template.php @@ -2118,14 +2118,17 @@ function _admin_search_query() { * * @global string $hook_suffix * @global string $admin_body_class + * @global string $body_id * @global WP_Locale $wp_locale WordPress date and time locale object. * * @param string $title Optional. Title of the Iframe page. Default empty. * @param bool $deprecated Not used. */ function iframe_header( $title = '', $deprecated = false ) { + global $hook_suffix, $admin_body_class, $body_id, $wp_locale; + show_admin_bar( false ); - global $hook_suffix, $admin_body_class, $wp_locale; + $admin_body_class = preg_replace( '/[^a-z0-9_-]+/i', '-', $hook_suffix ); $current_screen = get_current_screen(); @@ -2179,10 +2182,7 @@ var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php', 'relative' ) ); ? ?> </head> <?php - /** - * @global string $body_id - */ - $admin_body_id = isset( $GLOBALS['body_id'] ) ? 'id="' . $GLOBALS['body_id'] . '" ' : ''; + $admin_body_id = isset( $body_id ) ? 'id="' . $body_id . '" ' : ''; /** This filter is documented in wp-admin/admin-header.php */ $admin_body_classes = apply_filters( 'admin_body_class', '' ); @@ -2540,22 +2540,22 @@ function compression_test() { * * @see get_submit_button() * - * @param string $text The text of the button (defaults to 'Save Changes') + * @param string $text Optional. The text of the button. Defaults to 'Save Changes'. * @param string $type Optional. The type and CSS class(es) of the button. Core values * include 'primary', 'small', and 'large'. Default 'primary'. - * @param string $name The HTML name of the submit button. Defaults to "submit". If no - * id attribute is given in $other_attributes below, $name will be - * used as the button's id. - * @param bool $wrap True if the output button should be wrapped in a paragraph tag, - * false otherwise. Defaults to true. - * @param array|string $other_attributes Other attributes that should be output with the button, mapping - * attributes to their values, such as setting tabindex to 1, etc. - * These key/value attribute pairs will be output as attribute="value", - * where attribute is the key. Other attributes can also be provided - * as a string such as 'tabindex="1"', though the array format is - * preferred. Default null. + * @param string $name Optional. The HTML name of the submit button. If no `id` attribute + * is given in the `$other_attributes` parameter, `$name` will be used + * as the button's `id`. Default 'submit'. + * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph tag, + * false otherwise. Default true. + * @param array|string $other_attributes Optional. Other attributes that should be output with the button, + * mapping attributes to their values, e.g. `array( 'id' => 'search-submit' )`. + * These key/value attribute pairs will be output as `attribute="value"`, + * where attribute is the key. Attributes can also be provided as a string, + * e.g. `id="search-submit"`, though the array format is generally preferred. + * Default empty string. */ -function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) { +function submit_button( $text = '', $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = '' ) { echo get_submit_button( $text, $type, $name, $wrap, $other_attributes ); } @@ -2564,20 +2564,20 @@ function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap * * @since 3.1.0 * - * @param string $text Optional. The text of the button. Default 'Save Changes'. + * @param string $text Optional. The text of the button. Defaults to 'Save Changes'. * @param string $type Optional. The type and CSS class(es) of the button. Core values * include 'primary', 'small', and 'large'. Default 'primary large'. - * @param string $name Optional. The HTML name of the submit button. Defaults to "submit". - * If no id attribute is given in $other_attributes below, `$name` will - * be used as the button's id. Default 'submit'. - * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph - * tag, false otherwise. Default true. + * @param string $name Optional. The HTML name of the submit button. If no `id` attribute + * is given in the `$other_attributes` parameter, `$name` will be used + * as the button's `id`. Default 'submit'. + * @param bool $wrap Optional. True if the output button should be wrapped in a paragraph tag, + * false otherwise. Default true. * @param array|string $other_attributes Optional. Other attributes that should be output with the button, - * mapping attributes to their values, such as `array( 'tabindex' => '1' )`. - * These attributes will be output as `attribute="value"`, such as - * `tabindex="1"`. Other attributes can also be provided as a string such - * as `tabindex="1"`, though the array format is typically cleaner. - * Default empty. + * mapping attributes to their values, e.g. `array( 'id' => 'search-submit' )`. + * These key/value attribute pairs will be output as `attribute="value"`, + * where attribute is the key. Attributes can also be provided as a string, + * e.g. `id="search-submit"`, though the array format is generally preferred. + * Default empty string. * @return string Submit button HTML. */ function get_submit_button( $text = '', $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = '' ) { diff --git a/wp-admin/includes/theme-install.php b/wp-admin/includes/theme-install.php index 949f0d5..6faedc9 100644 --- a/wp-admin/includes/theme-install.php +++ b/wp-admin/includes/theme-install.php @@ -204,7 +204,7 @@ function install_themes_upload() { ?> </label> <input type="file" id="themezip" name="themezip" accept=".zip" /> - <?php submit_button( __( 'Install Now' ), '', 'install-theme-submit', false ); ?> + <?php submit_button( _x( 'Install Now', 'theme' ), '', 'install-theme-submit', false ); ?> </form> <?php } diff --git a/wp-admin/includes/theme.php b/wp-admin/includes/theme.php index f822e57..36dc28b 100644 --- a/wp-admin/includes/theme.php +++ b/wp-admin/includes/theme.php @@ -66,7 +66,7 @@ function delete_theme( $stylesheet, $redirect = '' ) { return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors ); } - // Get the base plugin folder. + // Get the base theme folder. $themes_dir = $wp_filesystem->wp_themes_dir(); if ( empty( $themes_dir ) ) { return new WP_Error( 'fs_no_themes_dir', __( 'Unable to locate WordPress theme directory.' ) ); @@ -114,6 +114,7 @@ function delete_theme( $stylesheet, $redirect = '' ) { foreach ( $translations as $translation => $data ) { $wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.po' ); $wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.mo' ); + $wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.l10n.php' ); $json_translation_files = glob( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '-*.json' ); if ( $json_translation_files ) { @@ -447,7 +448,7 @@ function get_theme_feature_list( $api = true ) { * * @since 2.8.0 * - * @param string $action API action to perform: 'query_themes', 'theme_information', + * @param string $action API action to perform: Accepts 'query_themes', 'theme_information', * 'hot_tags' or 'feature_list'. * @param array|object $args { * Optional. Array or object of arguments to serialize for the Themes API. Default empty array. @@ -1110,6 +1111,8 @@ function customize_themes_print_templates() { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_themes + * * @param string $theme Path to the theme directory relative to the themes directory. * @return bool True, if in the list of paused themes. False, not in the list. */ @@ -1130,6 +1133,8 @@ function is_theme_paused( $theme ) { * * @since 5.2.0 * + * @global WP_Paused_Extensions_Storage $_paused_themes + * * @param string $theme Path to the theme directory relative to the themes * directory. * @return array|false Array of error information as it was returned by @@ -1159,12 +1164,17 @@ function wp_get_theme_error( $theme ) { * * @since 5.2.0 * + * @global string $wp_stylesheet_path Path to current theme's stylesheet directory. + * @global string $wp_template_path Path to current theme's template directory. + * * @param string $theme Single theme to resume. * @param string $redirect Optional. URL to redirect to. Default empty string. * @return bool|WP_Error True on success, false if `$theme` was not paused, * `WP_Error` on failure. */ function resume_theme( $theme, $redirect = '' ) { + global $wp_stylesheet_path, $wp_template_path; + list( $extension ) = explode( '/', $theme ); /* @@ -1172,14 +1182,11 @@ function resume_theme( $theme, $redirect = '' ) { * creating a fatal error. */ if ( ! empty( $redirect ) ) { - $stylesheet_path = get_stylesheet_directory(); - $template_path = get_template_directory(); - $functions_path = ''; - if ( str_contains( $stylesheet_path, $extension ) ) { - $functions_path = $stylesheet_path . '/functions.php'; - } elseif ( str_contains( $template_path, $extension ) ) { - $functions_path = $template_path . '/functions.php'; + if ( str_contains( $wp_stylesheet_path, $extension ) ) { + $functions_path = $wp_stylesheet_path . '/functions.php'; + } elseif ( str_contains( $wp_template_path, $extension ) ) { + $functions_path = $wp_template_path . '/functions.php'; } if ( ! empty( $functions_path ) ) { @@ -1218,7 +1225,8 @@ function resume_theme( $theme, $redirect = '' ) { * * @since 5.2.0 * - * @global string $pagenow The filename of the current screen. + * @global string $pagenow The filename of the current screen. + * @global WP_Paused_Extensions_Storage $_paused_themes */ function paused_themes_notice() { if ( 'themes.php' === $GLOBALS['pagenow'] ) { diff --git a/wp-admin/includes/update-core.php b/wp-admin/includes/update-core.php index c767834..fd00326 100644 --- a/wp-admin/includes/update-core.php +++ b/wp-admin/includes/update-core.php @@ -37,8 +37,6 @@ $_old_files = array( 'wp-images/wp-small.png', 'wp-images/wpminilogo.png', 'wp.php', - // 2.0.8 - 'wp-includes/js/tinymce/plugins/inlinepopups/readme.txt', // 2.1 'wp-admin/edit-form-ajax-cat.php', 'wp-admin/execute-pings.php', @@ -52,8 +50,6 @@ $_old_files = array( 'wp-includes/functions-formatting.php', 'wp-includes/functions-post.php', 'wp-includes/js/dbx-key.js', - 'wp-includes/js/tinymce/plugins/autosave/langs/cs.js', - 'wp-includes/js/tinymce/plugins/autosave/langs/sv.js', 'wp-includes/links.php', 'wp-includes/pluggable-functions.php', 'wp-includes/template-functions-author.php', @@ -64,7 +60,6 @@ $_old_files = array( 'wp-includes/wp-l10n.php', // 2.2 'wp-admin/cat-js.php', - 'wp-admin/import/b2.php', 'wp-includes/js/autosave-js.php', 'wp-includes/js/list-manipulation-js.php', 'wp-includes/js/wp-ajax-js.php', @@ -108,39 +103,19 @@ $_old_files = array( 'wp-admin/js/link-cat.js', 'wp-admin/profile-update.php', 'wp-admin/templates.php', - 'wp-includes/images/wlw/WpComments.png', - 'wp-includes/images/wlw/WpIcon.png', - 'wp-includes/images/wlw/WpWatermark.png', 'wp-includes/js/dbx.js', 'wp-includes/js/fat.js', 'wp-includes/js/list-manipulation.js', 'wp-includes/js/tinymce/langs/en.js', - 'wp-includes/js/tinymce/plugins/autosave/editor_plugin_src.js', - 'wp-includes/js/tinymce/plugins/autosave/langs', 'wp-includes/js/tinymce/plugins/directionality/images', 'wp-includes/js/tinymce/plugins/directionality/langs', - 'wp-includes/js/tinymce/plugins/inlinepopups/css', - 'wp-includes/js/tinymce/plugins/inlinepopups/images', - 'wp-includes/js/tinymce/plugins/inlinepopups/jscripts', 'wp-includes/js/tinymce/plugins/paste/images', 'wp-includes/js/tinymce/plugins/paste/jscripts', 'wp-includes/js/tinymce/plugins/paste/langs', - 'wp-includes/js/tinymce/plugins/spellchecker/classes/HttpClient.class.php', - 'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyGoogleSpell.class.php', - 'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyPspell.class.php', - 'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyPspellShell.class.php', - 'wp-includes/js/tinymce/plugins/spellchecker/css/spellchecker.css', - 'wp-includes/js/tinymce/plugins/spellchecker/images', - 'wp-includes/js/tinymce/plugins/spellchecker/langs', - 'wp-includes/js/tinymce/plugins/spellchecker/tinyspell.php', 'wp-includes/js/tinymce/plugins/wordpress/images', 'wp-includes/js/tinymce/plugins/wordpress/langs', 'wp-includes/js/tinymce/plugins/wordpress/wordpress.css', 'wp-includes/js/tinymce/plugins/wphelp', - 'wp-includes/js/tinymce/themes/advanced/css', - 'wp-includes/js/tinymce/themes/advanced/images', - 'wp-includes/js/tinymce/themes/advanced/jscripts', - 'wp-includes/js/tinymce/themes/advanced/langs', // 2.5.1 'wp-includes/js/tinymce/tiny_mce_gzip.php', // 2.6 @@ -184,16 +159,11 @@ $_old_files = array( 'wp-includes/js/tinymce/tiny_mce_ext.js', // 2.8 'wp-admin/js/users.js', - 'wp-includes/js/swfupload/plugins/swfupload.documentready.js', - 'wp-includes/js/swfupload/plugins/swfupload.graceful_degradation.js', 'wp-includes/js/swfupload/swfupload_f9.swf', 'wp-includes/js/tinymce/plugins/autosave', 'wp-includes/js/tinymce/plugins/paste/css', 'wp-includes/js/tinymce/utils/mclayer.js', 'wp-includes/js/tinymce/wordpress.css', - // 2.8.5 - 'wp-admin/import/btt.php', - 'wp-admin/import/jkw.php', // 2.9 'wp-admin/js/page.dev.js', 'wp-admin/js/page.js', @@ -250,12 +220,9 @@ $_old_files = array( 'wp-admin/wp-admin.css', 'wp-admin/wp-admin.dev.css', 'wp-includes/js/codepress', - 'wp-includes/js/codepress/engines/khtml.js', - 'wp-includes/js/codepress/engines/older.js', 'wp-includes/js/jquery/autocomplete.dev.js', 'wp-includes/js/jquery/autocomplete.js', 'wp-includes/js/jquery/interface.js', - 'wp-includes/js/scriptaculous/prototype.js', // Following file added back in 5.1, see #45645. //'wp-includes/js/tinymce/wp-tinymce.js', // 3.1 @@ -277,7 +244,6 @@ $_old_files = array( 'wp-admin/sidebar.php', 'wp-includes/classes.php', 'wp-includes/js/tinymce/blank.htm', - 'wp-includes/js/tinymce/plugins/media/css/content.css', 'wp-includes/js/tinymce/plugins/media/img', 'wp-includes/js/tinymce/plugins/safari', // 3.2 @@ -286,11 +252,6 @@ $_old_files = array( 'wp-admin/js/list-table.dev.js', 'wp-admin/js/list-table.js', 'wp-includes/default-embeds.php', - 'wp-includes/js/tinymce/plugins/wordpress/img/help.gif', - 'wp-includes/js/tinymce/plugins/wordpress/img/more.gif', - 'wp-includes/js/tinymce/plugins/wordpress/img/toolbars.gif', - 'wp-includes/js/tinymce/themes/advanced/img/fm.gif', - 'wp-includes/js/tinymce/themes/advanced/img/sflogo.png', // 3.3 'wp-admin/css/colors-classic-rtl.css', 'wp-admin/css/colors-classic-rtl.dev.css', @@ -346,12 +307,6 @@ $_old_files = array( 'wp-includes/js/tinymce/plugins/wplink/css', 'wp-includes/js/tinymce/plugins/wplink/img', 'wp-includes/js/tinymce/plugins/wplink/js', - 'wp-includes/js/tinymce/themes/advanced/img/wpicons.png', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/butt2.png', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/button_bg.png', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/down_arrow.gif', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/fade-butt.png', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/separator.gif', // Don't delete, yet: 'wp-rss.php', // Don't delete, yet: 'wp-rdf.php', // Don't delete, yet: 'wp-rss2.php', @@ -365,27 +320,14 @@ $_old_files = array( 'wp-admin/index-extra.php', 'wp-admin/network/index-extra.php', 'wp-admin/user/index-extra.php', - 'wp-admin/images/screenshots/admin-flyouts.png', - 'wp-admin/images/screenshots/coediting.png', - 'wp-admin/images/screenshots/drag-and-drop.png', - 'wp-admin/images/screenshots/help-screen.png', - 'wp-admin/images/screenshots/media-icon.png', - 'wp-admin/images/screenshots/new-feature-pointer.png', - 'wp-admin/images/screenshots/welcome-screen.png', 'wp-includes/css/editor-buttons.css', 'wp-includes/css/editor-buttons.dev.css', 'wp-includes/js/tinymce/plugins/paste/blank.htm', 'wp-includes/js/tinymce/plugins/wordpress/css', 'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.dev.js', - 'wp-includes/js/tinymce/plugins/wordpress/img/embedded.png', - 'wp-includes/js/tinymce/plugins/wordpress/img/more_bug.gif', - 'wp-includes/js/tinymce/plugins/wordpress/img/page_bug.gif', 'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.dev.js', - 'wp-includes/js/tinymce/plugins/wpeditimage/css/editimage-rtl.css', 'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.dev.js', - 'wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin.dev.js', 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.dev.js', - 'wp-includes/js/tinymce/plugins/wpgallery/img/gallery.png', 'wp-includes/js/tinymce/plugins/wplink/editor_plugin.dev.js', // Don't delete, yet: 'wp-pass.php', // Don't delete, yet: 'wp-register.php', @@ -500,9 +442,6 @@ $_old_files = array( 'wp-admin/js/inline-edit-post.dev.js', 'wp-admin/js/categories.dev.js', 'wp-admin/js/editor.dev.js', - 'wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.dev.js', - 'wp-includes/js/tinymce/plugins/wpdialogs/js/popup.dev.js', - 'wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.dev.js', 'wp-includes/js/plupload/handlers.dev.js', 'wp-includes/js/plupload/wp-plupload.dev.js', 'wp-includes/js/swfupload/handlers.dev.js', @@ -529,21 +468,11 @@ $_old_files = array( 'wp-includes/js/jquery/ui/jquery.effects.pulsate.min.js', 'wp-includes/js/jquery/ui/jquery.effects.transfer.min.js', 'wp-includes/js/jquery/ui/jquery.effects.fold.min.js', - 'wp-admin/images/screenshots/captions-1.png', - 'wp-admin/images/screenshots/captions-2.png', - 'wp-admin/images/screenshots/flex-header-1.png', - 'wp-admin/images/screenshots/flex-header-2.png', - 'wp-admin/images/screenshots/flex-header-3.png', - 'wp-admin/images/screenshots/flex-header-media-library.png', - 'wp-admin/images/screenshots/theme-customizer.png', - 'wp-admin/images/screenshots/twitter-embed-1.png', - 'wp-admin/images/screenshots/twitter-embed-2.png', 'wp-admin/js/utils.js', // Added back in 5.3 [45448], see #43895. // 'wp-admin/options-privacy.php', 'wp-app.php', 'wp-includes/class-wp-atom-server.php', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/ui.css', // 3.5.2 'wp-includes/js/swfupload/swfupload-all.js', // 3.6 @@ -556,10 +485,7 @@ $_old_files = array( // 3.7 'wp-admin/js/cat.js', 'wp-admin/js/cat.min.js', - 'wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.min.js', // 3.8 - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/page_bug.gif', - 'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/more_bug.gif', 'wp-includes/js/thickbox/tb-close-2x.png', 'wp-includes/js/thickbox/tb-close.png', 'wp-includes/images/wpmini-blue-2x.png', @@ -630,7 +556,6 @@ $_old_files = array( 'wp-includes/js/tinymce/plugins/wpeditimage/js', 'wp-includes/js/tinymce/plugins/wpeditimage/css', 'wp-includes/js/tinymce/plugins/wpgallery/img', - 'wp-includes/js/tinymce/plugins/wpfullscreen/css', 'wp-includes/js/tinymce/plugins/paste/js', 'wp-includes/js/tinymce/themes/advanced', 'wp-includes/js/tinymce/tiny_mce.js', @@ -659,8 +584,6 @@ $_old_files = array( 'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js', 'wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js', - 'wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin.js', - 'wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin_src.js', 'wp-includes/js/tinymce/plugins/paste/editor_plugin.js', 'wp-includes/js/tinymce/plugins/paste/pasteword.htm', 'wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js', @@ -750,27 +673,6 @@ $_old_files = array( 'wp-includes/js/swfupload/swfupload.swf', // 4.9.2 'wp-includes/js/mediaelement/lang', - 'wp-includes/js/mediaelement/lang/ca.js', - 'wp-includes/js/mediaelement/lang/cs.js', - 'wp-includes/js/mediaelement/lang/de.js', - 'wp-includes/js/mediaelement/lang/es.js', - 'wp-includes/js/mediaelement/lang/fa.js', - 'wp-includes/js/mediaelement/lang/fr.js', - 'wp-includes/js/mediaelement/lang/hr.js', - 'wp-includes/js/mediaelement/lang/hu.js', - 'wp-includes/js/mediaelement/lang/it.js', - 'wp-includes/js/mediaelement/lang/ja.js', - 'wp-includes/js/mediaelement/lang/ko.js', - 'wp-includes/js/mediaelement/lang/nl.js', - 'wp-includes/js/mediaelement/lang/pl.js', - 'wp-includes/js/mediaelement/lang/pt.js', - 'wp-includes/js/mediaelement/lang/ro.js', - 'wp-includes/js/mediaelement/lang/ru.js', - 'wp-includes/js/mediaelement/lang/sk.js', - 'wp-includes/js/mediaelement/lang/sv.js', - 'wp-includes/js/mediaelement/lang/uk.js', - 'wp-includes/js/mediaelement/lang/zh-cn.js', - 'wp-includes/js/mediaelement/lang/zh.js', 'wp-includes/js/mediaelement/mediaelement-flash-audio-ogg.swf', 'wp-includes/js/mediaelement/mediaelement-flash-audio.swf', 'wp-includes/js/mediaelement/mediaelement-flash-video-hls.swf', @@ -787,7 +689,6 @@ $_old_files = array( // 5.0 'wp-includes/js/codemirror/jshint.js', // 5.1 - 'wp-includes/random_compat/random_bytes_openssl.php', 'wp-includes/js/tinymce/wp-tinymce.js.gz', // 5.3 'wp-includes/js/wp-a11y.js', // Moved to: wp-includes/js/dist/a11y.js @@ -822,7 +723,6 @@ $_old_files = array( 'wp-includes/block-patterns/text-two-columns-with-images.php', 'wp-includes/block-patterns/text-two-columns.php', 'wp-includes/block-patterns/large-header-button.php', - 'wp-includes/blocks/subhead/block.json', 'wp-includes/blocks/subhead', 'wp-includes/css/dist/editor/editor-styles.css', 'wp-includes/css/dist/editor/editor-styles.min.css', @@ -833,10 +733,6 @@ $_old_files = array( 'wp-includes/blocks/heading/editor.min.css', 'wp-includes/blocks/heading/editor-rtl.css', 'wp-includes/blocks/heading/editor-rtl.min.css', - 'wp-includes/blocks/post-content/editor.css', - 'wp-includes/blocks/post-content/editor.min.css', - 'wp-includes/blocks/post-content/editor-rtl.css', - 'wp-includes/blocks/post-content/editor-rtl.min.css', 'wp-includes/blocks/query-title/editor.css', 'wp-includes/blocks/query-title/editor.min.css', 'wp-includes/blocks/query-title/editor-rtl.css', @@ -847,21 +743,7 @@ $_old_files = array( 'wp-includes/blocks/tag-cloud/editor-rtl.min.css', // 6.1 'wp-includes/blocks/post-comments.php', - 'wp-includes/blocks/post-comments/block.json', - 'wp-includes/blocks/post-comments/editor.css', - 'wp-includes/blocks/post-comments/editor.min.css', - 'wp-includes/blocks/post-comments/editor-rtl.css', - 'wp-includes/blocks/post-comments/editor-rtl.min.css', - 'wp-includes/blocks/post-comments/style.css', - 'wp-includes/blocks/post-comments/style.min.css', - 'wp-includes/blocks/post-comments/style-rtl.css', - 'wp-includes/blocks/post-comments/style-rtl.min.css', 'wp-includes/blocks/post-comments', - 'wp-includes/blocks/comments-query-loop/block.json', - 'wp-includes/blocks/comments-query-loop/editor.css', - 'wp-includes/blocks/comments-query-loop/editor.min.css', - 'wp-includes/blocks/comments-query-loop/editor-rtl.css', - 'wp-includes/blocks/comments-query-loop/editor-rtl.min.css', 'wp-includes/blocks/comments-query-loop', // 6.3 'wp-includes/images/wlw', @@ -871,6 +753,18 @@ $_old_files = array( 'wp-includes/navigation-fallback.php', 'wp-includes/blocks/navigation/view-modal.min.js', 'wp-includes/blocks/navigation/view-modal.js', + // 6.5 + 'wp-includes/ID3/license.commercial.txt', + 'wp-includes/blocks/query/style-rtl.min.css', + 'wp-includes/blocks/query/style.min.css', + 'wp-includes/blocks/query/style-rtl.css', + 'wp-includes/blocks/query/style.css', + 'wp-admin/images/about-header-privacy.svg', + 'wp-admin/images/about-header-about.svg', + 'wp-admin/images/about-header-credits.svg', + 'wp-admin/images/about-header-freedoms.svg', + 'wp-admin/images/about-header-contribute.svg', + 'wp-admin/images/about-header-background.svg', ); /** @@ -1008,7 +902,7 @@ $_new_bundled_files = array( * Upgrades the core of WordPress. * * This will create a .maintenance file at the base of the WordPress directory - * to ensure that people can not access the web site, when the files are being + * to ensure that people can not access the website, when the files are being * copied to their locations. * * The files in the `$_old_files` list will be removed and the new files @@ -1093,7 +987,7 @@ function update_core( $from, $to ) { */ apply_filters( 'update_feedback', __( 'Verifying the unpacked files…' ) ); - // Sanity check the unzipped distribution. + // Confidence check the unzipped distribution. $distro = ''; $roots = array( '/wordpress/', '/wordpress-mu/' ); @@ -1848,13 +1742,14 @@ function _upgrade_440_force_deactivate_incompatible_plugins() { * @since 5.9.0 The minimum compatible version of Gutenberg is 11.9. * @since 6.1.1 The minimum compatible version of Gutenberg is 14.1. * @since 6.4.0 The minimum compatible version of Gutenberg is 16.5. + * @since 6.5.0 The minimum compatible version of Gutenberg is 17.6. */ function _upgrade_core_deactivate_incompatible_plugins() { - if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '16.5', '<' ) ) { + if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '17.6', '<' ) ) { $deactivated_gutenberg['gutenberg'] = array( 'plugin_name' => 'Gutenberg', 'version_deactivated' => GUTENBERG_VERSION, - 'version_compatible' => '16.5', + 'version_compatible' => '17.6', ); if ( is_plugin_active_for_network( 'gutenberg/gutenberg.php' ) ) { $deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins', array() ); diff --git a/wp-admin/includes/update.php b/wp-admin/includes/update.php index 7e68440..ba27ddd 100644 --- a/wp-admin/includes/update.php +++ b/wp-admin/includes/update.php @@ -1076,7 +1076,7 @@ function wp_recovery_mode_nag() { * * @since 5.5.0 * - * @param string $type The type of update being checked: 'theme' or 'plugin'. + * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @return bool True if auto-updates are enabled for `$type`, false otherwise. */ function wp_is_auto_update_enabled_for_type( $type ) { @@ -1116,7 +1116,7 @@ function wp_is_auto_update_enabled_for_type( $type ) { * * @since 5.6.0 * - * @param string $type The type of update being checked: 'theme' or 'plugin'. + * @param string $type The type of update being checked: Either 'theme' or 'plugin'. * @param bool|null $update Whether to update. The value of null is internally used * to detect whether nothing has hooked into this filter. * @param object $item The update offer. diff --git a/wp-admin/includes/upgrade.php b/wp-admin/includes/upgrade.php index 6929570..cb39391 100644 --- a/wp-admin/includes/upgrade.php +++ b/wp-admin/includes/upgrade.php @@ -843,6 +843,10 @@ function upgrade_all() { upgrade_640(); } + if ( $wp_current_db_version < 57155 ) { + upgrade_650(); + } + maybe_disable_link_manager(); maybe_disable_automattic_widgets(); @@ -2350,6 +2354,35 @@ function upgrade_640() { } /** + * Executes changes made in WordPress 6.5.0. + * + * @ignore + * @since 6.5.0 + * + * @global int $wp_current_db_version The old (current) database version. + * @global wpdb $wpdb WordPress database abstraction object. + */ +function upgrade_650() { + global $wp_current_db_version, $wpdb; + + if ( $wp_current_db_version < 57155 ) { + $stylesheet = get_stylesheet(); + + // Set autoload=no for all themes except the current one. + $theme_mods_options = $wpdb->get_col( + $wpdb->prepare( + "SELECT option_name FROM $wpdb->options WHERE autoload = 'yes' AND option_name != %s AND option_name LIKE %s", + "theme_mods_$stylesheet", + $wpdb->esc_like( 'theme_mods_' ) . '%' + ) + ); + + $autoload = array_fill_keys( $theme_mods_options, 'no' ); + wp_set_option_autoload_values( $autoload ); + } +} + +/** * Executes network-level upgrade routines. * * @since 3.0.0 @@ -2910,31 +2943,29 @@ function dbDelta( $queries = '', $execute = true ) { // phpcs:ignore WordPress.N */ // Extract type, name and columns from the definition. - // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation preg_match( - '/^' - . '(?P<index_type>' // 1) Type of the index. - . 'PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPATIAL)\s+(?:KEY|INDEX)|KEY|INDEX' - . ')' - . '\s+' // Followed by at least one white space character. - . '(?:' // Name of the index. Optional if type is PRIMARY KEY. - . '`?' // Name can be escaped with a backtick. - . '(?P<index_name>' // 2) Name of the index. - . '(?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+' - . ')' - . '`?' // Name can be escaped with a backtick. - . '\s+' // Followed by at least one white space character. - . ')*' - . '\(' // Opening bracket for the columns. - . '(?P<index_columns>' - . '.+?' // 3) Column names, index prefixes, and orders. - . ')' - . '\)' // Closing bracket for the columns. - . '$/im', + '/^ + (?P<index_type> # 1) Type of the index. + PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPATIAL)\s+(?:KEY|INDEX)|KEY|INDEX + ) + \s+ # Followed by at least one white space character. + (?: # Name of the index. Optional if type is PRIMARY KEY. + `? # Name can be escaped with a backtick. + (?P<index_name> # 2) Name of the index. + (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ + ) + `? # Name can be escaped with a backtick. + \s+ # Followed by at least one white space character. + )* + \( # Opening bracket for the columns. + (?P<index_columns> + .+? # 3) Column names, index prefixes, and orders. + ) + \) # Closing bracket for the columns. + $/imx', $fld, $index_matches ); - // phpcs:enable // Uppercase the index type and normalize space characters. $index_type = strtoupper( preg_replace( '/\s+/', ' ', trim( $index_matches['index_type'] ) ) ); @@ -2952,29 +2983,27 @@ function dbDelta( $queries = '', $execute = true ) { // phpcs:ignore WordPress.N // Normalize columns. foreach ( $index_columns as $id => &$index_column ) { // Extract column name and number of indexed characters (sub_part). - // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation preg_match( - '/' - . '`?' // Name can be escaped with a backtick. - . '(?P<column_name>' // 1) Name of the column. - . '(?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+' - . ')' - . '`?' // Name can be escaped with a backtick. - . '(?:' // Optional sub part. - . '\s*' // Optional white space character between name and opening bracket. - . '\(' // Opening bracket for the sub part. - . '\s*' // Optional white space character after opening bracket. - . '(?P<sub_part>' - . '\d+' // 2) Number of indexed characters. - . ')' - . '\s*' // Optional white space character before closing bracket. - . '\)' // Closing bracket for the sub part. - . ')?' - . '/', + '/ + `? # Name can be escaped with a backtick. + (?P<column_name> # 1) Name of the column. + (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ + ) + `? # Name can be escaped with a backtick. + (?: # Optional sub part. + \s* # Optional white space character between name and opening bracket. + \( # Opening bracket for the sub part. + \s* # Optional white space character after opening bracket. + (?P<sub_part> + \d+ # 2) Number of indexed characters. + ) + \s* # Optional white space character before closing bracket. + \) # Closing bracket for the sub part. + )? + /x', $index_column, $index_column_matches ); - // phpcs:enable // Escape the column name with backticks. $index_column = '`' . $index_column_matches['column_name'] . '`'; diff --git a/wp-admin/includes/user.php b/wp-admin/includes/user.php index 423c13a..abed2d2 100644 --- a/wp-admin/includes/user.php +++ b/wp-admin/includes/user.php @@ -638,7 +638,7 @@ Please click the following link to activate your user account: * * @since 5.6.0 * @since 6.2.0 Allow insecure HTTP connections for the local environment. - * @since 6.3.2 Validates the success and reject URLs to prevent javascript pseudo protocol being executed. + * @since 6.3.2 Validates the success and reject URLs to prevent `javascript` pseudo protocol from being executed. * * @param array $request { * The array of request data. All arguments are optional and may be empty. @@ -700,12 +700,11 @@ function wp_is_authorize_application_password_request_valid( $request, $user ) { } /** - * Validates the redirect URL protocol scheme. The protocol can be anything except http and javascript. + * Validates the redirect URL protocol scheme. The protocol can be anything except `http` and `javascript`. * * @since 6.3.2 * - * @param string $url - The redirect URL to be validated. - * + * @param string $url The redirect URL to be validated. * @return true|WP_Error True if the redirect URL is valid, a WP_Error object otherwise. */ function wp_is_authorize_application_redirect_url_valid( $url ) { @@ -728,16 +727,17 @@ function wp_is_authorize_application_redirect_url_valid( $url ) { * * @since 6.3.2 * - * @param string[] $bad_protocols Array of invalid protocols. - * @param string $url The redirect URL to be validated. + * @param string[] $bad_protocols Array of invalid protocols. + * @param string $url The redirect URL to be validated. */ - $invalid_protocols = array_map( 'strtolower', apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ) ); + $invalid_protocols = apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ); + $invalid_protocols = array_map( 'strtolower', $invalid_protocols ); $scheme = wp_parse_url( $url, PHP_URL_SCHEME ); $host = wp_parse_url( $url, PHP_URL_HOST ); $is_local = 'local' === wp_get_environment_type(); - // validates if the proper URI format is applied to the $url + // Validates if the proper URI format is applied to the URL. if ( empty( $host ) || empty( $scheme ) || in_array( strtolower( $scheme ), $invalid_protocols, true ) ) { return new WP_Error( 'invalid_redirect_url_format', |