Changeset 63708
- Timestamp:
- 09/17/2026 09:05:55 PM (3 hours ago)
- Location:
- branches/5.4
- Files:
-
- 11 edited
-
. (modified) (1 prop)
-
src/js/_enqueues/wp/theme.js (modified) (2 diffs)
-
src/wp-admin/includes/ajax-actions.php (modified) (2 diffs)
-
src/wp-admin/includes/class-custom-image-header.php (modified) (4 diffs)
-
src/wp-admin/includes/plugin.php (modified) (1 diff)
-
src/wp-admin/includes/post.php (modified) (1 diff)
-
src/wp-includes/class-wp-xmlrpc-server.php (modified) (1 diff)
-
src/wp-includes/customize/class-wp-customize-header-image-setting.php (modified) (2 diffs)
-
src/wp-includes/formatting.php (modified) (1 diff)
-
src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php (modified) (3 diffs)
-
src/wp-includes/theme.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/5.4
- Property svn:mergeinfo changed
/trunk merged: 62658,63656-63657,63659-63660,63665,63669,63672,63675
- Property svn:mergeinfo changed
-
branches/5.4/src/js/_enqueues/wp/theme.js
r47122 r63708 1932 1932 1933 1933 1934 /* 1935 * jQuery.escapeSelector() (added in jQuery 3.0) is not available on this 1936 * branch's vendored jQuery. Fall back to the native CSS.escape(), which is 1937 * what jQuery.escapeSelector() delegates to and which jQuery UI polyfills 1938 * it with. A browser with neither skips the preview route below rather 1939 * than building a selector from an unescaped slug. 1940 */ 1941 var escapeSelector = $.escapeSelector || ( window.CSS && window.CSS.escape && function( sel ) { 1942 return window.CSS.escape( sel + '' ); 1943 } ); 1944 1934 1945 themes.RunInstaller = { 1935 1946 … … 1994 2005 self.view.collection.trigger( 'update' ); 1995 2006 1996 // Open the theme preview. 2007 // Open the theme preview. The slug comes from the URL, so escape it. 1997 2008 self.view.collection.once( 'query:success', function() { 1998 $( 'div[data-slug="' + slug + '"]' ).trigger( 'click' ); 2009 if ( ! escapeSelector ) { 2010 return; 2011 } 2012 2013 $( 'div.theme[data-slug="' + escapeSelector( slug ) + '"]' ).trigger( 'click' ); 1999 2014 }); 2000 2015 -
branches/5.4/src/wp-admin/includes/ajax-actions.php
r56878 r63708 1952 1952 check_ajax_referer( 'getpermalink', 'getpermalinknonce' ); 1953 1953 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; 1954 if ( ! $post_id ) { 1955 // Bypass call to get_preview_post_link() for unspecified post ID. 1956 wp_die( '' ); 1957 } 1958 if ( ! current_user_can( 'edit_post', $post_id ) ) { 1959 wp_die( -1 ); 1960 } 1954 1961 wp_die( get_preview_post_link( $post_id ) ); 1955 1962 } … … 1963 1970 check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' ); 1964 1971 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; 1965 $title = isset( $_POST['new_title'] ) ? $_POST['new_title'] : ''; 1966 $slug = isset( $_POST['new_slug'] ) ? $_POST['new_slug'] : null; 1972 if ( ! $post_id ) { 1973 // Bypass call to get_sample_permalink_html() for unspecified post ID. 1974 wp_die( '' ); 1975 } 1976 if ( ! current_user_can( 'edit_post', $post_id ) ) { 1977 wp_die( -1 ); 1978 } 1979 $title = isset( $_POST['new_title'] ) ? $_POST['new_title'] : ''; 1980 $slug = isset( $_POST['new_slug'] ) ? $_POST['new_slug'] : null; 1967 1981 wp_die( get_sample_permalink_html( $post_id, $title, $slug ) ); 1968 1982 } -
branches/5.4/src/wp-admin/includes/class-custom-image-header.php
r49391 r63708 529 529 } 530 530 ?> 531 <div id="headimg" style="<?php echo $header_image_style; ?>">531 <div id="headimg" style="<?php echo esc_attr( $header_image_style ); ?>"> 532 532 <?php 533 533 if ( display_header_text() ) { … … 1088 1088 'url' => $choice['url'], 1089 1089 'thumbnail_url' => $choice['url'], 1090 'height' => $choice['height'],1091 'width' => $choice['width'],1090 'height' => absint( $choice['height'] ), 1091 'width' => absint( $choice['width'] ), 1092 1092 ); 1093 1093 … … 1117 1117 } 1118 1118 1119 set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) ); 1119 $header_image_data['url'] = esc_url_raw( $header_image_data['url'] ); 1120 1121 if ( isset( $header_image_data['thumbnail_url'] ) ) { 1122 $header_image_data['thumbnail_url'] = esc_url_raw( $header_image_data['thumbnail_url'] ); 1123 } 1124 1125 set_theme_mod( 'header_image', $header_image_data['url'] ); 1120 1126 set_theme_mod( 'header_image_data', $header_image_data ); 1121 1127 } … … 1478 1484 1479 1485 foreach ( $header_images as &$header_image ) { 1480 $header_meta = get_post_meta( $header_image['attachment_id'] ); 1481 $header_image['timestamp'] = isset( $header_meta[ $timestamp_key ] ) ? $header_meta[ $timestamp_key ] : ''; 1482 $header_image['alt_text'] = isset( $header_meta[ $alt_text_key ] ) ? $header_meta[ $alt_text_key ] : ''; 1486 $header_image['timestamp'] = get_post_meta( $header_image['attachment_id'], $timestamp_key, true ); 1487 $header_image['alt_text'] = get_post_meta( $header_image['attachment_id'], $alt_text_key, true ); 1483 1488 } 1484 1489 -
branches/5.4/src/wp-admin/includes/plugin.php
r47219 r63708 584 584 * 585 585 * @since 3.0.0 586 * 587 * @param string $plugin Path to the plugin file relative to the plugins directory. 586 * @since 7.1.1 The `$plugin` path is normalized with `plugin_basename()` and `trim()`, 587 * matching how `activate_plugin()` resolves it. 588 * 589 * @param string $plugin Path to the plugin file. Accepts a path relative to the plugins 590 * directory, or an absolute path, with or without surrounding whitespace. 588 591 * @return bool True if plugin is network only, false otherwise. 589 592 */ 590 593 function is_network_only_plugin( $plugin ) { 594 // Normalize the path the same way activate_plugin() does, so both agree on the file. 595 $plugin = plugin_basename( trim( $plugin ) ); 596 591 597 $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); 592 598 if ( $plugin_data ) { -
branches/5.4/src/wp-admin/includes/post.php
r54559 r63708 22 22 if ( empty( $post_data ) ) { 23 23 $post_data = &$_POST; 24 } 25 26 /* 27 * A raw `ID` on the create path (no `post_ID`) is an attempt to overwrite an 28 * existing post while bypassing the per-post capability checks below, which only 29 * run on the update path. Reject it outright: legitimate post creation never 30 * carries an `ID`. 31 */ 32 if ( ! $update && ! empty( $post_data['ID'] ) ) { 33 if ( 'page' === $post_data['post_type'] ) { 34 return new WP_Error( 'edit_others_pages', __( 'Sorry, you are not allowed to edit pages as this user.' ) ); 35 } else { 36 return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to edit posts as this user.' ) ); 37 } 24 38 } 25 39 -
branches/5.4/src/wp-includes/class-wp-xmlrpc-server.php
r49391 r63708 1393 1393 } 1394 1394 1395 // Reject writes to internal-only builtin post types (e.g. customize_changeset) 1396 // whose intended write path is a dedicated helper, not a generic post API. 1397 $is_internal_only = ( 1398 empty( $post_type->public ) 1399 && empty( $post_type->show_in_rest ) 1400 && ! empty( $post_type->_builtin ) 1401 ); 1402 1403 /** 1404 * Filters whether a post type accepts writes via XML-RPC. 1405 * 1406 * Defaults to false for internal-only builtin post types (public=false, 1407 * show_in_rest=false, _builtin=true), such as customize_changeset, whose 1408 * writes are meant to flow through dedicated helpers. Return true to opt 1409 * a post type back in. 1410 * 1411 * @since 7.1.1 1412 * 1413 * @param bool $allowed Whether the post type accepts XML-RPC writes. 1414 * @param WP_Post_Type $post_type The post type object. 1415 */ 1416 $allowed = apply_filters( 'xmlrpc_allow_post_type_writes', ! $is_internal_only, $post_type ); 1417 1418 if ( ! $allowed ) { 1419 return new IXR_Error( 403, __( 'Sorry, this post type is not supported over XML-RPC.' ) ); 1420 } 1421 1395 1422 $update = ! empty( $post_data['ID'] ); 1396 1423 -
branches/5.4/src/wp-includes/customize/class-wp-customize-header-image-setting.php
r47198 r63708 16 16 * 17 17 * @see WP_Customize_Setting 18 * 19 * @phpstan-type Header_Image_Data array{ 20 * attachment_id?: int, 21 * url?: string, 22 * thumbnail_url?: string, 23 * timestamp?: int, 24 * width?: int, 25 * height?: int, 26 * alt_text?: string, 27 * attachment_parent?: int, 28 * } 18 29 */ 19 30 final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting { … … 51 62 } 52 63 } 64 65 /** 66 * Sanitizes a header value. 67 * 68 * The value is expected to be one of the following: 69 * 70 * - An array of header image data, with the keys `attachment_id`, `url`, `thumbnail_url`, `timestamp`, `width`, 71 * `height`, `alt_text`, and `attachment_parent`, as supplied by {@see get_uploaded_header_images()}. Any other 72 * key is discarded. 73 * - An array with a `choice` key, being the legacy format in which any of the other accepted values is nested. 74 * - The string `remove-header`, `random-default-image`, or `random-uploaded-image`. 75 * - A string corresponding to one of the keys for the array returned by {@see get_uploaded_header_images()}, or 76 * one of the keys for the array passed into {@see register_default_headers()}. 77 * 78 * @since 7.1.1 79 * 80 * @see WP_Customize_Header_Image_Setting::update() 81 * @see Custom_Image_Header::set_header_image() 82 * 83 * @param mixed $value Value to sanitize. 84 * @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid. The array holds 85 * the header image data, or that data nested under a `choice` key, 86 * before the `customize_sanitize_header_image_data` filter, which 87 * may return anything, is applied to it. 88 * 89 * @phpstan-return array<mixed, mixed>|string|WP_Error|null 90 */ 91 public function sanitize( $value ) { 92 /* 93 * The update() method unwraps the legacy `choice` format before handing the value off to 94 * Custom_Image_Header::set_header_image(), so the nested value is what must be sanitized. 95 */ 96 if ( is_array( $value ) && isset( $value['choice'] ) ) { 97 $choice = $this->sanitize_choice( $value['choice'] ); 98 if ( is_null( $choice ) || is_wp_error( $choice ) ) { 99 return $choice; 100 } 101 $value = array( 'choice' => $choice ); 102 } else { 103 $value = $this->sanitize_choice( $value ); 104 if ( is_null( $value ) || is_wp_error( $value ) ) { 105 return $value; 106 } 107 } 108 109 return parent::sanitize( $value ); 110 } 111 112 /** 113 * Sanitizes a header image choice. 114 * 115 * This is the value which is ultimately passed to {@see Custom_Image_Header::set_header_image()}, whether 116 * supplied at the top level of the setting value or nested under its legacy `choice` key. 117 * 118 * @since 7.1.1 119 * 120 * @param mixed $value Value to sanitize. 121 * @return array|string|WP_Error|null Sanitized value, or `null`/`WP_Error` if invalid. 122 * 123 * @phpstan-return Header_Image_Data|string|WP_Error|null 124 */ 125 private function sanitize_choice( $value ) { 126 // Custom_Image_Header::set_header_image() accepts an object in place of an array. 127 if ( is_object( $value ) ) { 128 $value = (array) $value; 129 } 130 131 if ( is_string( $value ) ) { 132 return sanitize_text_field( $value ); 133 } 134 135 if ( ! is_array( $value ) ) { 136 return null; 137 } 138 139 /* 140 * The sanitized value is assembled member by member rather than filtered down from the 141 * supplied one, so that nothing but the members below can end up in it. 142 */ 143 $sanitized = array(); 144 145 if ( isset( $value['attachment_id'] ) ) { 146 if ( ! is_scalar( $value['attachment_id'] ) ) { 147 return null; 148 } 149 $attachment_id = absint( $value['attachment_id'] ); 150 151 /* 152 * A supplied attachment must be an existing image, since its ID is written to postmeta and its 153 * data displayed. Note that an ID of zero must be skipped rather than looked up, as 154 * get_post_mime_type() falls back to the global post when passed an empty value. 155 */ 156 if ( $attachment_id > 0 ) { 157 $mime_type = get_post_mime_type( $attachment_id ); 158 if ( ! is_string( $mime_type ) || ! str_starts_with( $mime_type, 'image/' ) ) { 159 return null; 160 } 161 } 162 163 $sanitized['attachment_id'] = $attachment_id; 164 } 165 166 if ( isset( $value['url'] ) ) { 167 if ( ! is_string( $value['url'] ) ) { 168 return null; 169 } 170 $sanitized['url'] = esc_url_raw( $value['url'] ); 171 if ( '' === $sanitized['url'] ) { 172 return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) ); 173 } 174 } 175 176 if ( isset( $value['thumbnail_url'] ) ) { 177 if ( ! is_string( $value['thumbnail_url'] ) ) { 178 return null; 179 } 180 $sanitized['thumbnail_url'] = esc_url_raw( $value['thumbnail_url'] ); 181 if ( '' === $sanitized['thumbnail_url'] ) { 182 return new WP_Error( 'invalid_url', __( 'Invalid URL.' ) ); 183 } 184 } 185 186 if ( isset( $value['timestamp'] ) ) { 187 if ( ! is_scalar( $value['timestamp'] ) ) { 188 return null; 189 } 190 $sanitized['timestamp'] = absint( $value['timestamp'] ); 191 } 192 193 if ( isset( $value['width'] ) ) { 194 if ( ! is_scalar( $value['width'] ) ) { 195 return null; 196 } 197 $sanitized['width'] = absint( $value['width'] ); 198 } 199 200 if ( isset( $value['height'] ) ) { 201 if ( ! is_scalar( $value['height'] ) ) { 202 return null; 203 } 204 $sanitized['height'] = absint( $value['height'] ); 205 } 206 207 if ( isset( $value['alt_text'] ) ) { 208 if ( ! is_string( $value['alt_text'] ) ) { 209 return null; 210 } 211 $sanitized['alt_text'] = sanitize_text_field( $value['alt_text'] ); 212 } 213 214 if ( isset( $value['attachment_parent'] ) ) { 215 if ( ! is_scalar( $value['attachment_parent'] ) ) { 216 return null; 217 } 218 $sanitized['attachment_parent'] = absint( $value['attachment_parent'] ); 219 } 220 221 return $sanitized; 222 } 53 223 } -
branches/5.4/src/wp-includes/formatting.php
r55785 r63708 573 573 574 574 // If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>. 575 $pee = preg_replace( ' |<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $pee );575 $pee = preg_replace( '!<p><blockquote((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>!i', '<blockquote$1><p>', $pee ); 576 576 $pee = str_replace( '</blockquote></p>', '</p></blockquote>', $pee ); 577 577 -
branches/5.4/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
r47391 r63708 769 769 * 770 770 * @since 4.7.0 771 * @since 7.1.0 Target post permissions are checked when a comment's parent post is changed. 771 772 * 772 773 * @param WP_REST_Request $request Full details about the request. … … 785 786 array( 'status' => rest_authorization_required_code() ) 786 787 ); 788 } 789 790 /* 791 * check_edit_permission() above only establishes that the comment may be 792 * edited where it currently sits, because 'edit_comment' maps to 'edit_post' 793 * on the comment's current parent. When the parent is being changed, the new 794 * parent has to be authorized as well. Without this, a user holding 795 * edit_comment on their own comment could reparent it onto any post, 796 * including posts they can neither read nor edit. 797 */ 798 if ( isset( $request['post'] ) && (int) $request['post'] !== (int) $comment->comment_post_ID ) { 799 $target_check = $this->check_target_post_permission( (int) $request['post'] ); 800 801 if ( is_wp_error( $target_check ) ) { 802 return $target_check; 803 } 787 804 } 788 805 … … 1869 1886 return $email; 1870 1887 } 1888 1889 /** 1890 * Checks that a post can receive a comment from the current user. 1891 * 1892 * Used when changing the parent post of an existing comment, so that 1893 * attaching a comment to a post is authorized the same way whichever 1894 * path it arrives by. 1895 * 1896 * @since 7.1.0 1897 * 1898 * @param int $post_id Target post ID. 1899 * @return true|WP_Error True if the post can receive the comment, error object otherwise. 1900 */ 1901 protected function check_target_post_permission( $post_id ) { 1902 if ( ! $post_id ) { 1903 return new WP_Error( 1904 'rest_comment_invalid_post_id', 1905 __( 'Sorry, you are not allowed to create this comment without a post.' ), 1906 array( 'status' => 403 ) 1907 ); 1908 } 1909 1910 /* 1911 * A comment needs either comment moderation rights or edit access to the 1912 * post, which is what check_edit_permission() grants on the post a comment 1913 * is moving away from. Requiring the same at the destination means both 1914 * ends of a move are authorized alike. 1915 */ 1916 if ( ! current_user_can( 'moderate_comments' ) && ! current_user_can( 'edit_post', $post_id ) ) { 1917 return new WP_Error( 1918 'rest_cannot_edit', 1919 __( 'Sorry, you are not allowed to edit this comment.' ), 1920 array( 'status' => rest_authorization_required_code() ) 1921 ); 1922 } 1923 1924 $post = get_post( $post_id ); 1925 1926 if ( ! $post ) { 1927 return new WP_Error( 1928 'rest_comment_invalid_post_id', 1929 __( 'Sorry, you are not allowed to create this comment without a post.' ), 1930 array( 'status' => 403 ) 1931 ); 1932 } 1933 1934 /* 1935 * The create-time draft and comments-open rules are deliberately not applied 1936 * here, because moderators move comments onto posts whose discussion has 1937 * closed and onto drafts today. Enforcing them would break that without 1938 * blocking anything the capability check above already permits. 1939 */ 1940 return true; 1941 } 1871 1942 } -
branches/5.4/src/wp-includes/theme.php
r47267 r63708 1322 1322 * 1323 1323 * @since 3.4.0 1324 * @since 7.1.1 The `width` and `height` are cast to non-negative integers. 1324 1325 * 1325 1326 * @global array $_wp_default_headers … … 1360 1361 'video' => get_theme_support( 'custom-header', 'video' ), 1361 1362 ); 1362 return (object) wp_parse_args( $data, $default ); 1363 1364 if ( ! is_array( $data ) && ! is_object( $data ) ) { 1365 $data = array(); 1366 } 1367 $header = (object) wp_parse_args( $data, $default ); 1368 $header->width = absint( $header->width ); 1369 $header->height = absint( $header->height ); 1370 return $header; 1363 1371 } 1364 1372
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)