Changeset 46915
- Timestamp:
- 12/12/2019 06:51:11 PM (5 years ago)
- Location:
- branches/5.0
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/5.0
- Property svn:mergeinfo changed
/trunk merged: 46893-46896
- Property svn:mergeinfo changed
-
branches/5.0/src/wp-includes/blocks.php
r43924 r46915 75 75 * @see parse_blocks() 76 76 * 77 * @param string $block_ type Full Block type to look for.77 * @param string $block_name Full Block type to look for. 78 78 * @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object. Defaults to global $post. 79 79 * @return bool Whether the post content contains the specified block. 80 80 */ 81 function has_block( $block_ type, $post = null ) {81 function has_block( $block_name, $post = null ) { 82 82 if ( ! has_blocks( $post ) ) { 83 83 return false; … … 91 91 } 92 92 93 return false !== strpos( $post, '<!-- wp:' . $block_type . ' ' ); 93 /* 94 * Normalize block name to include namespace, if provided as non-namespaced. 95 * This matches behavior for WordPress 5.0.0 - 5.3.0 in matching blocks by 96 * their serialized names. 97 */ 98 if ( false === strpos( $block_name, '/' ) ) { 99 $block_name = 'core/' . $block_name; 100 } 101 102 // Test for existence of block by its fully qualified name. 103 $has_block = false !== strpos( $post, '<!-- wp:' . $block_name . ' ' ); 104 105 if ( ! $has_block ) { 106 /* 107 * If the given block name would serialize to a different name, test for 108 * existence by the serialized form. 109 */ 110 $serialized_block_name = strip_core_block_namespace( $block_name ); 111 if ( $serialized_block_name !== $block_name ) { 112 $has_block = false !== strpos( $post, '<!-- wp:' . $serialized_block_name . ' ' ); 113 } 114 } 115 116 return $has_block; 94 117 } 95 118 … … 112 135 113 136 return $dynamic_block_names; 137 } 138 139 /** 140 * Given an array of attributes, returns a string in the serialized attributes 141 * format prepared for post content. 142 * 143 * The serialized result is a JSON-encoded string, with unicode escape sequence 144 * substitution for characters which might otherwise interfere with embedding 145 * the result in an HTML comment. 146 * 147 * @since 5.3.1 148 * 149 * @param array $attributes Attributes object. 150 * @return string Serialized attributes. 151 */ 152 function serialize_block_attributes( $block_attributes ) { 153 $encoded_attributes = json_encode( $block_attributes ); 154 $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes ); 155 $encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes ); 156 $encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes ); 157 $encoded_attributes = preg_replace( '/&/', '\\u0026', $encoded_attributes ); 158 // Regex: /\\"/ 159 $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes ); 160 161 return $encoded_attributes; 162 } 163 164 /** 165 * Returns the block name to use for serialization. This will remove the default 166 * "core/" namespace from a block name. 167 * 168 * @since 5.3.1 169 * 170 * @param string $block_name Original block name. 171 * @return string Block name to use for serialization. 172 */ 173 function strip_core_block_namespace( $block_name = null ) { 174 if ( is_string( $block_name ) && 0 === strpos( $block_name, 'core/' ) ) { 175 return substr( $block_name, 5 ); 176 } 177 178 return $block_name; 179 } 180 181 /** 182 * Returns the content of a block, including comment delimiters. 183 * 184 * @since 5.3.1 185 * 186 * @param string $block_name Block name. 187 * @param array $attributes Block attributes. 188 * @param string $content Block save content. 189 * @return string Comment-delimited block content. 190 */ 191 function get_comment_delimited_block_content( $block_name = null, $block_attributes, $block_content ) { 192 if ( is_null( $block_name ) ) { 193 return $block_content; 194 } 195 196 $serialized_block_name = strip_core_block_namespace( $block_name ); 197 $serialized_attributes = empty( $block_attributes ) ? '' : serialize_block_attributes( $block_attributes ) . ' '; 198 199 if ( empty( $block_content ) ) { 200 return sprintf( '<!-- wp:%s %s/-->', $serialized_block_name, $serialized_attributes ); 201 } 202 203 return sprintf( 204 '<!-- wp:%s %s-->%s<!-- /wp:%s -->', 205 $serialized_block_name, 206 $serialized_attributes, 207 $block_content, 208 $serialized_block_name 209 ); 210 } 211 212 /** 213 * Returns the content of a block, including comment delimiters, serializing all 214 * attributes from the given parsed block. 215 * 216 * This should be used when preparing a block to be saved to post content. 217 * Prefer `render_block` when preparing a block for display. Unlike 218 * `render_block`, this does not evaluate a block's `render_callback`, and will 219 * instead preserve the markup as parsed. 220 * 221 * @since 5.3.1 222 * 223 * @param WP_Block_Parser_Block $block A single parsed block object. 224 * @return string String of rendered HTML. 225 */ 226 function serialize_block( $block ) { 227 $block_content = ''; 228 229 $index = 0; 230 foreach ( $block['innerContent'] as $chunk ) { 231 $block_content .= is_string( $chunk ) ? $chunk : serialize_block( $block['innerBlocks'][ $index++ ] ); 232 } 233 234 if ( ! is_array( $block['attrs'] ) ) { 235 $block['attrs'] = array(); 236 } 237 238 return get_comment_delimited_block_content( 239 $block['blockName'], 240 $block['attrs'], 241 $block_content 242 ); 243 } 244 245 /** 246 * Returns a joined string of the aggregate serialization of the given parsed 247 * blocks. 248 * 249 * @since 5.3.1 250 * 251 * @param WP_Block_Parser_Block[] $blocks Parsed block objects. 252 * @return string String of rendered HTML. 253 */ 254 function serialize_blocks( $blocks ) { 255 return implode( '', array_map( 'serialize_block', $blocks ) ); 256 } 257 258 /** 259 * Filters and sanitizes block content to remove non-allowable HTML from 260 * parsed block attribute values. 261 * 262 * @since 5.3.1 263 * 264 * @param string $text Text that may contain block content. 265 * @param array[]|string $allowed_html An array of allowed HTML elements 266 * and attributes, or a context name 267 * such as 'post'. 268 * @param string[] $allowed_protocols Array of allowed URL protocols. 269 * @return string The filtered and sanitized content result. 270 */ 271 function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols = array() ) { 272 $result = ''; 273 274 $blocks = parse_blocks( $text ); 275 foreach ( $blocks as $block ) { 276 $block = filter_block_kses( $block, $allowed_html, $allowed_protocols ); 277 $result .= serialize_block( $block ); 278 } 279 280 return $result; 281 } 282 283 /** 284 * Filters and sanitizes a parsed block to remove non-allowable HTML from block 285 * attribute values. 286 * 287 * @since 5.3.1 288 * 289 * @param WP_Block_Parser_Block $block The parsed block object. 290 * @param array[]|string $allowed_html An array of allowed HTML 291 * elements and attributes, or a 292 * context name such as 'post'. 293 * @param string[] $allowed_protocols Allowed URL protocols. 294 * @return array The filtered and sanitized block object result. 295 */ 296 function filter_block_kses( $block, $allowed_html, $allowed_protocols = array() ) { 297 $block['attrs'] = filter_block_kses_value( $block['attrs'], $allowed_html, $allowed_protocols ); 298 299 if ( is_array( $block['innerBlocks'] ) ) { 300 foreach ( $block['innerBlocks'] as $i => $inner_block ) { 301 $block['innerBlocks'][ $i ] = filter_block_kses( $inner_block, $allowed_html, $allowed_protocols ); 302 } 303 } 304 305 return $block; 306 } 307 308 /** 309 * Filters and sanitizes a parsed block attribute value to remove non-allowable 310 * HTML. 311 * 312 * @since 5.3.1 313 * 314 * @param mixed $value The attribute value to filter. 315 * @param array[]|string $allowed_html An array of allowed HTML elements 316 * and attributes, or a context name 317 * such as 'post'. 318 * @param string[] $allowed_protocols Array of allowed URL protocols. 319 * @return array The filtered and sanitized result. 320 */ 321 function filter_block_kses_value( $value, $allowed_html, $allowed_protocols = array() ) { 322 if ( is_array( $value ) ) { 323 foreach ( $value as $key => $inner_value ) { 324 $filtered_key = filter_block_kses_value( $key, $allowed_html, $allowed_protocols ); 325 $filtered_value = filter_block_kses_value( $inner_value, $allowed_html, $allowed_protocols ); 326 327 if ( $filtered_key !== $key ) { 328 unset( $value[ $key ] ); 329 } 330 331 $value[ $filtered_key ] = $filtered_value; 332 } 333 } elseif ( is_string( $value ) ) { 334 return wp_kses( $value, $allowed_html, $allowed_protocols ); 335 } 336 337 return $value; 114 338 } 115 339 -
branches/5.0/src/wp-includes/default-filters.php
r43930 r46915 225 225 226 226 // Misc filters 227 add_filter( 'option_ping_sites', 'privacy_ping_filter' ); 228 add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop 229 add_filter( 'option_blog_charset', '_canonical_charset' ); 230 add_filter( 'option_home', '_config_wp_home' ); 231 add_filter( 'option_siteurl', '_config_wp_siteurl' ); 232 add_filter( 'tiny_mce_before_init', '_mce_set_direction' ); 233 add_filter( 'teeny_mce_before_init', '_mce_set_direction' ); 234 add_filter( 'pre_kses', 'wp_pre_kses_less_than' ); 235 add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 ); 236 add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); 237 add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 ); 238 add_filter( 'pre_comment_content', 'wp_rel_nofollow', 15 ); 239 add_filter( 'comment_email', 'antispambot' ); 240 add_filter( 'option_tag_base', '_wp_filter_taxonomy_base' ); 241 add_filter( 'option_category_base', '_wp_filter_taxonomy_base' ); 242 add_filter( 'the_posts', '_close_comments_for_old_posts', 10, 2); 243 add_filter( 'comments_open', '_close_comments_for_old_post', 10, 2 ); 244 add_filter( 'pings_open', '_close_comments_for_old_post', 10, 2 ); 245 add_filter( 'editable_slug', 'urldecode' ); 246 add_filter( 'editable_slug', 'esc_textarea' ); 247 add_filter( 'nav_menu_meta_box_object', '_wp_nav_menu_meta_box_object' ); 248 add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' ); 249 add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' ); 250 add_filter( 'title_save_pre', 'trim' ); 227 add_filter( 'option_ping_sites', 'privacy_ping_filter' ); 228 add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop 229 add_filter( 'option_blog_charset', '_canonical_charset' ); 230 add_filter( 'option_home', '_config_wp_home' ); 231 add_filter( 'option_siteurl', '_config_wp_siteurl' ); 232 add_filter( 'tiny_mce_before_init', '_mce_set_direction' ); 233 add_filter( 'teeny_mce_before_init', '_mce_set_direction' ); 234 add_filter( 'pre_kses', 'wp_pre_kses_less_than' ); 235 add_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10, 3 ); 236 add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 ); 237 add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); 238 add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 ); 239 add_filter( 'pre_comment_content', 'wp_rel_nofollow', 15 ); 240 add_filter( 'comment_email', 'antispambot' ); 241 add_filter( 'option_tag_base', '_wp_filter_taxonomy_base' ); 242 add_filter( 'option_category_base', '_wp_filter_taxonomy_base' ); 243 add_filter( 'the_posts', '_close_comments_for_old_posts', 10, 2 ); 244 add_filter( 'comments_open', '_close_comments_for_old_post', 10, 2 ); 245 add_filter( 'pings_open', '_close_comments_for_old_post', 10, 2 ); 246 add_filter( 'editable_slug', 'urldecode' ); 247 add_filter( 'editable_slug', 'esc_textarea' ); 248 add_filter( 'nav_menu_meta_box_object', '_wp_nav_menu_meta_box_object' ); 249 add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' ); 250 add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' ); 251 add_filter( 'title_save_pre', 'trim' ); 251 252 252 253 add_action( 'transition_comment_status', '_clear_modified_cache_on_transition_comment_status', 10, 2 ); -
branches/5.0/src/wp-includes/formatting.php
r45993 r46915 4404 4404 4405 4405 /** 4406 * Remove non-allowable HTML from parsed block attribute values when filtering 4407 * in the post context. 4408 * 4409 * @since 5.3.1 4410 * 4411 * @param string $string Content to be run through KSES. 4412 * @param array[]|string $allowed_html An array of allowed HTML elements 4413 * and attributes, or a context name 4414 * such as 'post'. 4415 * @param string[] $allowed_protocols Array of allowed URL protocols. 4416 * @return string Filtered text to run through KSES. 4417 */ 4418 function wp_pre_kses_block_attributes( $string, $allowed_html, $allowed_protocols ) { 4419 /* 4420 * `filter_block_content` is expected to call `wp_kses`. Temporarily remove 4421 * the filter to avoid recursion. 4422 */ 4423 remove_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10 ); 4424 $string = filter_block_content( $string, $allowed_html, $allowed_protocols ); 4425 add_filter( 'pre_kses', 'wp_pre_kses_block_attributes', 10, 3 ); 4426 4427 return $string; 4428 } 4429 4430 /** 4406 4431 * WordPress implementation of PHP sprintf() with filters. 4407 4432 * -
branches/5.0/src/wp-includes/kses.php
r46004 r46915 1409 1409 function wp_kses_bad_protocol_once($string, $allowed_protocols, $count = 1 ) { 1410 1410 $string = preg_replace( '/(�*58(?![;0-9])|�*3a(?![;a-f0-9]))/i', '$1;', $string ); 1411 $string2 = preg_split( '/:|�*58;|�*3a; /i', $string, 2 );1412 if ( isset( $string2[1]) && ! preg_match('%/\?%', $string2[0]) ) {1413 $string = trim( $string2[1] );1411 $string2 = preg_split( '/:|�*58;|�*3a;|:/i', $string, 2 ); 1412 if ( isset( $string2[1] ) && ! preg_match( '%/\?%', $string2[0] ) ) { 1413 $string = trim( $string2[1] ); 1414 1414 $protocol = wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols ); 1415 1415 if ( 'feed:' == $protocol ) { -
branches/5.0/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
r43862 r46915 492 492 } 493 493 494 if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) ) {494 if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) && ! current_user_can( $post_type->cap->publish_posts ) ) { 495 495 return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not allowed to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) ); 496 496 } … … 647 647 } 648 648 649 if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) ) {649 if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) && ! current_user_can( $post_type->cap->publish_posts ) ) { 650 650 return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not allowed to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) ); 651 651 } … … 945 945 */ 946 946 protected function prepare_item_for_database( $request ) { 947 $prepared_post = new stdClass ;947 $prepared_post = new stdClass(); 948 948 949 949 // Post ID. -
branches/5.0/tests/phpunit/tests/blocks/block-type.php
r43918 r46915 303 303 // even if it detects a proper $post global it should still be false for a missing block. 304 304 $this->assertFalse( has_block( 'core/fake' ) ); 305 } 306 307 public function test_post_has_block_serialized_name() { 308 $content = '<!-- wp:serialized /--><!-- wp:core/normalized /--><!-- wp:plugin/third-party /-->'; 309 310 $this->assertTrue( has_block( 'core/serialized', $content ) ); 311 312 /* 313 * Technically, `has_block` should receive a "full" (normalized, parsed) 314 * block name. But this test conforms to expected pre-5.3.1 behavior. 315 */ 316 $this->assertTrue( has_block( 'serialized', $content ) ); 317 $this->assertTrue( has_block( 'core/normalized', $content ) ); 318 $this->assertTrue( has_block( 'normalized', $content ) ); 319 $this->assertFalse( has_block( 'plugin/normalized', $content ) ); 320 $this->assertFalse( has_block( 'plugin/serialized', $content ) ); 321 $this->assertFalse( has_block( 'third-party', $content ) ); 322 $this->assertFalse( has_block( 'core/third-party', $content ) ); 305 323 } 306 324 -
branches/5.0/tests/phpunit/tests/kses.php
r46004 r46915 171 171 } 172 172 173 $bad_not_normalized = array( 174 'dummy:alert(1)', 175 'javascript:alert(1)', 176 'javascript&CoLon;alert(1)', 177 'javascript&COLON;alert(1);', 178 'javascript:alert(1);', 179 'javascript:alert(1);', 180 'javascript:alert(1);', 181 'jav ascript&COLON;alert(1);', 182 'javascript:javascript:alert(1);', 183 'javascript:javascript:alert(1);', 184 'javascript:javascript:alert(1);', 185 'javascript:javascript:alert(1);', 186 'javascript:alert(1)', 187 ); 188 foreach ( $bad_not_normalized as $k => $x ) { 189 $result = wp_kses_bad_protocol( $x, wp_allowed_protocols() ); 190 if ( ! empty( $result ) && 'alert(1);' !== $result && 'alert(1)' !== $result ) { 191 $this->fail( "wp_kses_bad_protocol failed on $k, $x. Result: $result" ); 192 } 193 } 194 173 195 $safe = array( 174 196 'dummy:alert(1)',
Note: See TracChangeset
for help on using the changeset viewer.