Changeset 61841
- Timestamp:
- 03/05/2026 10:17:34 AM (8 days ago)
- Location:
- trunk
- Files:
-
- 4 edited
-
src/wp-admin/includes/image.php (modified) (4 diffs)
-
src/wp-admin/includes/media.php (modified) (6 diffs)
-
src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php (modified) (3 diffs)
-
tests/phpunit/tests/image/meta.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/includes/image.php
r61291 r61841 814 814 * 815 815 * The IPTC metadata that is retrieved is APP13, credit, byline, created date 816 * and time, caption, copyright, a nd title. Also includes FNumber, Model,816 * and time, caption, copyright, alt, and title. Also includes FNumber, Model, 817 817 * DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime. 818 818 * … … 855 855 'orientation' => 0, 856 856 'keywords' => array(), 857 'alt' => '', 857 858 ); 858 859 … … 926 927 } 927 928 } 929 930 $meta['alt'] = wp_get_image_alttext( $file ); 928 931 929 932 $exif = array(); … … 1073 1076 */ 1074 1077 return apply_filters( 'wp_read_image_metadata', $meta, $file, $image_type, $iptc, $exif ); 1078 } 1079 1080 /** 1081 * Gets the alt text from image meta data. 1082 * 1083 * @since 7.0.0 1084 * 1085 * @param string $file File path to the image. 1086 * @return string Embedded alternative text. 1087 */ 1088 function wp_get_image_alttext( $file ) { 1089 $alt_text = ''; 1090 $img_contents = file_get_contents( $file ); 1091 // Find the start and end positions of the XMP metadata. 1092 $xmp_start = strpos( $img_contents, '<x:xmpmeta' ); 1093 $xmp_end = strpos( $img_contents, '</x:xmpmeta>' ); 1094 1095 if ( ! $xmp_start || ! $xmp_end ) { 1096 // No XMP metadata found. 1097 return $alt_text; 1098 } 1099 1100 // Extract the XMP metadata from the JPEG contents 1101 $xmp_data = substr( $img_contents, $xmp_start, $xmp_end - $xmp_start + 12 ); 1102 1103 // Parse the XMP metadata using DOMDocument. 1104 $doc = new DOMDocument(); 1105 if ( false === $doc->loadXML( $xmp_data ) ) { 1106 // Invalid XML in metadata. 1107 return $alt_text; 1108 } 1109 1110 // Instantiate an XPath object, used to extract portions of the XMP. 1111 $xpath = new DOMXPath( $doc ); 1112 1113 // Register the relevant XML namespaces. 1114 $xpath->registerNamespace( 'x', 'adobe:ns:meta/' ); 1115 $xpath->registerNamespace( 'rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' ); 1116 $xpath->registerNamespace( 'Iptc4xmpCore', 'http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/' ); 1117 1118 $node_list = $xpath->query( '/x:xmpmeta/rdf:RDF/rdf:Description/Iptc4xmpCore:AltTextAccessibility' ); 1119 if ( $node_list && $node_list->count() ) { 1120 1121 $node = $node_list->item( 0 ); 1122 1123 // Get the site's locale. 1124 $locale = get_locale(); 1125 1126 // Get the alt text accessibility alternative most appropriate for the site language. 1127 // There are 3 possibilities: 1128 // 1129 // 1. there is an rdf:li with an exact match on the site locale. 1130 // 2. there is an rdf:li with a partial match on the site locale (e.g., site locale is en_US and rdf:li has @xml:lang="en"). 1131 // 3. there is an rdf:li with an "x-default" lang. 1132 // 1133 // Evaluate in that order, stopping when we have a match. 1134 $alt_text = $xpath->evaluate( "string( rdf:Alt/rdf:li[ @xml:lang = '{$locale}' ] )", $node ); 1135 if ( ! $alt_text ) { 1136 $alt_text = $xpath->evaluate( 'string( rdf:Alt/rdf:li[ @xml:lang = "' . substr( $locale, 0, 2 ) . '" ] )', $node ); 1137 if ( ! $alt_text ) { 1138 $alt_text = $xpath->evaluate( 'string( rdf:Alt/rdf:li[ @xml:lang = "x-default" ] )', $node ); 1139 } 1140 } 1141 } 1142 1143 return $alt_text; 1075 1144 } 1076 1145 -
trunk/src/wp-admin/includes/media.php
r61681 r61841 320 320 $content = ''; 321 321 $excerpt = ''; 322 $alt = ''; 322 323 323 324 if ( preg_match( '#^audio#', $type ) ) { … … 400 401 $excerpt = $image_meta['caption']; 401 402 } 403 404 if ( trim( $image_meta['alt'] ) ) { 405 $alt = $image_meta['alt']; 406 } 402 407 } 403 408 } … … 422 427 $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true ); 423 428 429 if ( trim( $alt ) ) { 430 update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $alt ) ); 431 } 432 424 433 if ( ! is_wp_error( $attachment_id ) ) { 425 434 /* … … 478 487 $title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) ); 479 488 $content = ''; 489 $alt = ''; 480 490 481 491 // Use image exif/iptc data for title and caption defaults if possible. … … 489 499 if ( trim( $image_meta['caption'] ) ) { 490 500 $content = $image_meta['caption']; 501 } 502 if ( trim( $image_meta['alt'] ) ) { 503 $alt = $image_meta['alt']; 491 504 } 492 505 } … … 513 526 // Save the attachment metadata. 514 527 $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true ); 528 529 if ( trim( $alt ) ) { 530 update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $alt ) ); 531 } 515 532 516 533 if ( ! is_wp_error( $attachment_id ) ) { -
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
r61809 r61841 438 438 $type = $file['type']; 439 439 $file = $file['file']; 440 $alt = ''; 440 441 441 442 // Include image functions to get access to wp_read_image_metadata(). … … 452 453 if ( empty( $request['caption'] ) && trim( $image_meta['caption'] ) ) { 453 454 $request['caption'] = $image_meta['caption']; 455 } 456 457 if ( empty( $request['alt'] ) && trim( $image_meta['alt'] ) ) { 458 $alt = $image_meta['alt']; 454 459 } 455 460 } … … 477 482 // $post_parent is inherited from $attachment['post_parent']. 478 483 $id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true, false ); 484 485 if ( trim( $alt ) ) { 486 update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $alt ) ); 487 } 479 488 480 489 if ( is_wp_error( $id ) ) { -
trunk/tests/phpunit/tests/image/meta.php
r57987 r61841 128 128 $this->assertSame( '0', $out['shutter_speed'], 'Shutter speed value not equivalent' ); 129 129 $this->assertSame( '', $out['title'], 'Title value not the same' ); 130 } 131 132 /** 133 * @ticket 63895 134 */ 135 public function test_iptc_alt() { 136 // Image tests alt text from the IPTC photo metadata standard 2025.1. 137 $out = wp_read_image_metadata( DIR_TESTDATA . '/images/IPTC-PhotometadataRef-Std2025.1.jpg' ); 138 139 $this->assertSame( 'This is the Alt Text description to support accessibility in 2025.1', $out['alt'], 'Alt text does not match source.' ); 130 140 } 131 141 … … 201 211 'orientation' => '3', 202 212 'keywords' => array(), 213 'alt' => '', 203 214 ), 204 215 ), … … 218 229 'orientation' => '0', 219 230 'keywords' => array(), 231 'alt' => '', 220 232 ), 221 233 ), … … 235 247 'orientation' => '1', 236 248 'keywords' => array( 'beach', 'baywatch', 'LA', 'sunset' ), 249 'alt' => '', 237 250 ), 238 251 ),
Note: See TracChangeset
for help on using the changeset viewer.