diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php
index 0f03e2c..a729715 100644
--- a/src/wp-admin/includes/image.php
+++ b/src/wp-admin/includes/image.php
@@ -337,10 +337,27 @@ function wp_exif_date2ts( $str ) {
}
/**
+ * Convert the EXIF geographical longitude and latitude from degrees, minutes
+ * and seconds to degrees format.
+ *
+ * @since 5.0.0
+ *
+ * @param string $coordinate The coordinate to convert to degrees format.
+ * @return float Coordinate in degrees format.
+ */
+function wp_exif_gps_convert( $coordinate ) {
+ @list( $degree, $minute, $second ) = $coordinate;
+ $float = wp_exif_frac2dec( $degree ) + ( wp_exif_frac2dec( $minute ) / 60 ) + ( wp_exif_frac2dec( $second ) / 3600 );
+
+ return ( ( is_float( $float ) || ( is_int( $float ) && $degree == $float ) ) && ( abs( $float ) <= 180 ) ) ? $float : 999;
+}
+
+/**
* Get extended image metadata, exif or iptc as available.
*
* Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso
- * created_timestamp, focal_length, shutter_speed, and title.
+ * created_timestamp, focal_length, shutter_speed, title, and location
+ * (latitude & longitude).
*
* The IPTC metadata that is retrieved is APP13, credit, byline, created date
* and time, caption, copyright, and title. Also includes FNumber, Model,
@@ -501,6 +518,28 @@ function wp_read_image_metadata( $file ) {
if ( ! empty( $exif['Orientation'] ) ) {
$meta['orientation'] = $exif['Orientation'];
}
+
+ /**
+ * Filters whether geographical EXIF data should parsed and stored in
+ * meta.
+ *
+ * @param bool true Default is to parse geographical data.
+ */
+ $process_geo_data = (bool) apply_filters( 'wp_read_image_geo_data', true );
+
+ if ( $process_geo_data ) {
+ $meta['location'] = array(
+ 'longitude' => '',
+ 'latitude' => '',
+ );
+
+ if ( ! empty( $exif['GPSLongitude'] ) && count( $exif['GPSLongitude'] ) == 3 && ! empty( $exif['GPSLongitudeRef'] ) ) {
+ $meta['location']['longitude'] = round( ( $exif['GPSLongitudeRef'] == 'W' ? - 1 : 1 ) * wp_exif_gps_convert( $exif['GPSLongitude'] ), 7 );
+ }
+ if ( ! empty( $exif['GPSLatitude'] ) && count( $exif['GPSLatitude'] ) == 3 && ! empty( $exif['GPSLatitudeRef'] ) ) {
+ $meta['location']['latitude'] = round( ( $exif['GPSLatitudeRef'] == 'S' ? - 1 : 1 ) * wp_exif_gps_convert( $exif['GPSLatitude'] ), 7 );
+ }
+ }
}
foreach ( array( 'title', 'caption', 'credit', 'copyright', 'camera', 'iso' ) as $key ) {
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php
index 0dbba58..d9208f9 100644
--- a/src/wp-includes/media-template.php
+++ b/src/wp-includes/media-template.php
@@ -373,6 +373,9 @@ function wp_print_media_templates() {
<# if ( data.width && data.height ) { #>
{{ data.width }} × {{ data.height }}
<# } #>
+ <# if ( data.longitude && data.latitude ) { #>
+ {{ data.longitude }},{{ data.latitude }}
+ <# } #>
<# } #>
<# if ( data.fileLength ) { #>
diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
index 8965da9..409f922 100644
--- a/src/wp-includes/media.php
+++ b/src/wp-includes/media.php
@@ -3228,6 +3228,8 @@ function wp_prepare_attachment_for_js( $attachment ) {
'subtype' => $subtype,
'icon' => wp_mime_type_icon( $attachment->ID ),
'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ),
+ 'longitude' => $meta['image_meta']['location']['longitude'],
+ 'latitude' => $meta['image_meta']['location']['latitude'],
'nonces' => array(
'update' => false,
'delete' => false,
@@ -3289,7 +3291,7 @@ function wp_prepare_attachment_for_js( $attachment ) {
if ( current_user_can( 'delete_post', $attachment->ID ) ) {
$response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
}
-
+
if ( $meta && ( 'image' === $type || ! empty( $meta['sizes'] ) ) ) {
$sizes = array();
diff --git a/tests/phpunit/tests/image/meta.php b/tests/phpunit/tests/image/meta.php
index 0d791b9..b688881 100644
--- a/tests/phpunit/tests/image/meta.php
+++ b/tests/phpunit/tests/image/meta.php
@@ -31,6 +31,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 400, $out['iso'] );
$this->assertEquals( 1 / 40, $out['shutter_speed'] );
$this->assertEquals( '', $out['title'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
function test_exif_d70_mf() {
@@ -47,6 +48,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 0, $out['iso'] ); // interesting - a Nikon bug?
$this->assertEquals( 1 / 500, $out['shutter_speed'] );
$this->assertEquals( '', $out['title'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
#$this->assertEquals(array('Flowers'), $out['keywords']);
}
@@ -64,6 +66,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 200, $out['iso'] );
$this->assertEquals( 1 / 25, $out['shutter_speed'] );
$this->assertEquals( 'IPTC Headline', $out['title'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
function test_exif_fuji() {
@@ -80,7 +83,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 64, $out['iso'] );
$this->assertEquals( 1 / 320, $out['shutter_speed'] );
$this->assertEquals( '', $out['title'] );
-
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
/**
@@ -102,6 +105,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 0, $out['iso'] );
$this->assertEquals( 0, $out['shutter_speed'] );
$this->assertEquals( '', $out['title'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
function test_exif_no_data() {
@@ -118,6 +122,7 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 0, $out['iso'] );
$this->assertEquals( 0, $out['shutter_speed'] );
$this->assertEquals( '', $out['title'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
/**
@@ -160,6 +165,16 @@ class Tests_Image_Meta extends WP_UnitTestCase {
$this->assertEquals( 'Photoshop Document Ttitle', $out['title'] );
$this->assertEquals( 1, $out['orientation'] );
$this->assertEquals( array( 'beach', 'baywatch', 'LA', 'sunset' ), $out['keywords'] );
+ $this->assertEquals( array( 'longitude' => '', 'latitude' => '' ), $out['location'] );
}
+ /**
+ * @ticket 9257
+ */
+ function test_exif_location() {
+ $out = wp_read_image_metadata( DIR_TESTDATA . '/images/test-gps-location.jpg' );
+
+ $this->assertEquals( '39.0058333', $out['location']['longitude'] );
+ $this->assertEquals( '-69.0028333', $out['location']['latitude'] );
+ }
}