* @copyright Copyright (c) 2008 - 2017, Justin Tadlock * @link https://themehybrid.com/hybrid-core * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ /** * Gets attachment media file metadata. Each piece of meta will be escaped and formatted when * returned so that theme authors can properly utilize it within their themes. * * Theme authors shouldn't access this class directly. Instead, utilize the `hybrid_media_meta()` * and `hybrid_get_media_meta()` functions. * * @since 3.0.0 * @access public */ class Hybrid_Media_Meta { /** * Arguments passed in. * * @since 3.0.0 * @access protected * @var array */ protected $post_id = 0; /** * Metadata from the wp_get_attachment_metadata() function. * * @since 3.0.0 * @access protected * @var array */ protected $meta = array(); /** * Type of media for the current attachment. * * @since 3.0.0 * @access protected * @var string image|audio|video */ protected $type = ''; /** * Allowed media types. * * @since 3.0.0 * @access public * @var array */ protected $allowed_types = array( 'image', 'audio', 'video' ); /* ====== Magic Methods ====== */ /** * Sets up and runs the functionality for getting the attachment meta. * * @since 3.0.0 * @access public * @param array $args * @return void */ public function __construct( $post_id ) { $this->post_id = $post_id; $this->meta = wp_get_attachment_metadata( $this->post_id ); $this->type = hybrid_get_attachment_type( $this->post_id ); // If we have a type that's in the whitelist, run filters. if ( $this->type && in_array( $this->type, $this->allowed_types ) ) { // Run common media filters for any media type. $this->media_filters(); // Run type-specific filters. call_user_func( array( $this, "{$this->type}_filters" ) ); } } /** * Magic method for getting media object properties. Let's keep from failing if a theme * author attempts to access a property that doesn't exist. * * @since 3.0.0 * @access public * @param string $property * @return mixed */ public function __get( $property ) { return isset( $this->property ) ? $this->property : $this->get( $property ); } /* ====== Protected Methods ====== */ /** * Function for escaping properties when there is not a specific method for handling them * within the class. * * @since 3.0.0 * @access protected * @param string|int $value * @param string $property * @return string|int */ protected function escape( $value, $property ) { if ( has_filter( "hybrid_media_meta_escape_{$property}" ) ) return apply_filters( "hybrid_media_meta_escape_{$property}", $value, $this->type ); return is_numeric( $value ) ? intval( $value ) : esc_html( $value ); } /** * Adds filters for common media meta. * * Properties: file_name, filesize, file_type, mime_type * * @since 3.0.0 * @access protected * @return void */ protected function media_filters() { add_filter( 'hybrid_media_meta_escape_file_name', array( $this, 'file_name' ), 5 ); add_filter( 'hybrid_media_meta_escape_filesize', array( $this, 'file_size' ), 5 ); add_filter( 'hybrid_media_meta_escape_file_size', array( $this, 'file_size' ), 5 ); // alias for filesize add_filter( 'hybrid_media_meta_escape_file_type', array( $this, 'file_type' ), 5 ); add_filter( 'hybrid_media_meta_escape_mime_type', array( $this, 'mime_type' ), 5 ); } /** * Adds filters for image meta. * * Properties: aperture, camera, caption, copyright, credit, created_timestamp, dimensions, * focal_length, iso, shutter_speed * * @since 3.0.0 * @access protected * @return void */ protected function image_filters() { add_filter( 'hybrid_media_meta_escape_dimensions', array( $this, 'dimensions' ), 5 ); add_filter( 'hybrid_media_meta_escape_created_timestamp', array( $this, 'created_timestamp' ), 5 ); add_filter( 'hybrid_media_meta_escape_aperture', array( $this, 'aperture' ), 5 ); add_filter( 'hybrid_media_meta_escape_shutter_speed', array( $this, 'shutter_speed' ), 5 ); add_filter( 'hybrid_media_meta_escape_focal_length', 'absint', 5 ); add_filter( 'hybrid_media_meta_escape_iso', 'absint', 5 ); } /** * Adds filters for audio meta. * * Properties: album, artist, composer, genre, length_formatted, lyrics, track_number, year * * @since 3.0.0 * @access protected * @return void */ protected function audio_filters() { add_filter( 'hybrid_media_meta_escape_track_number', 'absint', 5 ); add_filter( 'hybrid_media_meta_escape_year', 'absint', 5 ); // Filters for the audio transcript. add_filter( 'hybrid_media_meta_escape_lyrics', array( $this, 'lyrics' ), 5 ); add_filter( 'hybrid_media_meta_escape_lyrics', 'wptexturize', 10 ); add_filter( 'hybrid_media_meta_escape_lyrics', 'convert_chars', 15 ); add_filter( 'hybrid_media_meta_escape_lyrics', 'wpautop', 20 ); } /** * Adds filters for video meta. * * Properties: dimensions, length-formatted * * @since 3.0.0 * @access protected * @return void */ protected function video_filters() { add_filter( 'hybrid_media_meta_escape_dimensions', array( $this, 'dimensions' ), 5 ); } /* ====== Public Methods ====== */ /** * Method for grabbing meta formatted metadata by key. * * @since 3.0.0 * @access public * @param string $property * @return mixed */ public function get( $property ) { $value = null; // If the property exists in the meta array. if ( isset( $this->meta[ $property ] ) ) $value = $this->meta[ $property ]; // If the property exists in the image meta array. elseif ( 'image' === $this->type && isset( $this->meta['image_meta'][ $property ] ) ) $value = $this->meta['image_meta'][ $property ]; // If the property exists in the video's audio meta array. elseif ( 'video' === $this->type && isset( $this->meta['audio'][ $property ] ) ) $value = $this->meta['audio'][ $property ]; // Escape and return. return $this->escape( $value, $property ); } /** * Image/Video meta. Media width + height dimensions. * * @since 3.0.0 * @access public * @param string $dimensions * @return string */ public function dimensions( $dimensions ) { // If there's a width and height. if ( ! empty( $this->meta['width'] ) && ! empty( $this->meta['height'] ) ) { $dimensions = sprintf( // Translators: Media dimensions - 1 is width and 2 is height. esc_html__( '%1$s × %2$s', 'hybrid-core' ), number_format_i18n( absint( $this->meta['width'] ) ), number_format_i18n( absint( $this->meta['height'] ) ) ); } return $dimensions; } /** * Image meta. Date the image was created. * * @since 3.0.0 * @access public * @param string $timestamp * @return string */ public function created_timestamp( $timestamp ) { if ( ! empty( $this->meta['image_meta']['created_timestamp'] ) ) { $timestamp = date_i18n( get_option( 'date_format' ), strip_tags( $this->meta['image_meta']['created_timestamp'] ) ); } return $timestamp; } /** * Image meta. Camera aperture in the form of `f/{$aperture}`. * * @since 3.0.0 * @access public * @param string $aperture * @return string */ public function aperture( $aperture ) { if ( !empty( $this->meta['image_meta']['aperture'] ) ) $aperture = sprintf( 'f%s', absint( $this->meta['image_meta']['aperture'] ) ); return $aperture; } /** * Image meta. Camera shutter speed in seconds (i18n number format). * * @since 3.0.0 * @access public * @param string $shutter * @return string */ public function shutter_speed( $shutter ) { // If a shutter speed is given, format the float into a fraction. if ( ! empty( $this->meta['image_meta']['shutter_speed'] ) ) { $shutter = $speed = floatval( strip_tags( $this->meta['image_meta']['shutter_speed'] ) ); if ( ( 1 / $speed ) > 1 ) { $shutter = sprintf( '%s⁄', number_format_i18n( 1 ) ); if ( number_format( ( 1 / $speed ), 1 ) == number_format( ( 1 / $speed ), 0 ) ) $shutter .= sprintf( '%s', number_format_i18n( ( 1 / $speed ), 0, '.', '' ) ); else $shutter .= sprintf( '%s', number_format_i18n( ( 1 / $speed ), 1, '.', '' ) ); } } return $shutter; } /** * Audio meta. Lyrics/transcript for an audio file. * * @since 3.0.0 * @access public * @return void */ public function lyrics( $lyrics ) { // Look for the 'unsynchronised_lyric' tag. if ( isset( $this->meta['unsynchronised_lyric'] ) ) $lyrics = $this->meta['unsynchronised_lyric']; // Seen this misspelling of the id3 tag. elseif ( isset( $this->meta['unsychronised_lyric'] ) ) $lyrics = $this->meta['unsychronised_lyric']; return strip_tags( $lyrics ); } /** * Name of the file linked to the permalink for the file. * * @since 3.0.0 * @access public * @return string */ public function file_name() { return sprintf( '%s', esc_url( wp_get_attachment_url( $this->post_id ) ), basename( get_attached_file( $this->post_id ) ) ); } /** * Audio/Video meta. Size of the file. * * @since 3.0.0 * @access public * @param int $file_size * @return int */ public function file_size( $file_size ) { return ! empty( $this->meta['filesize'] ) ? size_format( strip_tags( $this->meta['filesize'] ), 2 ) : $file_size; } /** * Type of file. * * @since 3.0.0 * @access public * @param string $file_type * @return string */ public function file_type( $file_type ) { if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $this->post_id ), $matches ) ) $file_type = esc_html( strtoupper( $matches[1] ) ); return $file_type; } /** * Mime type for the file. * * @since 3.0.0 * @access public * @param string $mime_type * @return string */ public function mime_type( $mime_type ) { $mime_type = get_post_mime_type( $this->post_id ); if ( empty( $mime_type ) && ! empty( $this->meta['mime_type'] ) ) $mime_type = $this->meta['mime_type']; return esc_html( $mime_type ); } }