Skip to content

Instantly share code, notes, and snippets.

@theMikeD
Created January 20, 2015 17:43
Show Gist options
  • Save theMikeD/8c83a7743218901bd904 to your computer and use it in GitHub Desktop.
Save theMikeD/8c83a7743218901bd904 to your computer and use it in GitHub Desktop.
Manipulates the metadata for uploaded images at upload time to make better use of IPTC data that may be present.
<?php
/*
Manipulates the metadata for uploaded images at upload time to make better use
of IPTC data that may be present.
An image is stored as an attachment, which is a special type of post. It is
handled the same way as any other post type.
As far as the meta goes, it's stored like this:
Image title is stored as post_title in wp_post,
Description is stored as post_content in wp_post,
Caption is stored as post_excerpt in wp_post
Alt Text is stored as _wp_attachment_image_alt in wp_postmeta
The rest of the meta data is stored as _wp_attachment_metadata as aa serialized
entry in wp_postmeta
When reading meta from the file during ingest, WP uses the following as its source,
in order of appearance:
Title:
1. IPTC:Headline
2. IPTC:Title
3. IPTC:Description if less than 80 characters
4. EXIF:Title (which doesn't actually exist)
5. EXIF:ImageDescription if less than 80 characters
6. Filename minus extension
Caption:
1. IPTC:Description
2. EXIF:UserComment if title is unset AND EXIF:ImageDescription is less than 80 characters
3. EXIF:ImageDescription if title is set OR EXIF:ImageDescription is more than 80 characters
4. EXIF:Comments if title !== EXIF:Comments
1. Image title = IPTC Headline
2. Image description = IPTC Description
Alt Text:
none
Description:
1. IPTC:Description if more than 80 characters
What this code does is the following:
1. Image title = IPTC Title if present, even if IPTC:Headline is set
2. Image caption = IPTC Headline
3. Image alt text = Image Caption (done is step 2) + comma-separated IPTC:Keywords
4. Image Description = IPTC:Description regardless of length
5. Add a new meta value called md_meta_update_complete to track whether these
adjustments have been done.
We can't do this at metadata collection time (such as by hoooking into
wp_read_image_metadata)because some of this info is stored as wp_post
and the entry doesn't exist at the time wp_read_image_metadata is running.
Logic Steps
1. Copy Title (post_title) to Caption (post_excerpt). Refer to default logic
above to understand why this is valid
2. If IPTC:Title, set Title (post_title) to IPTC:Title
3. Read in the IPTC Keywords and insert into Alt along with Caption
4. Readin IPTC:Description and insert into description (post_content)
*/
// Hook into add_attachment at the very end
add_filter('add_attachment', 'md_force_image_metadata', 99, 2);
/*******************************************************************************
Wrapper to call the steps in order.
@param int $image_id, attachment ID
@return none
*/
function md_force_image_metadata( $image_id ) {
$image_meta = wp_get_attachment_metadata( $image_id );
// Only run if it hasn't already been run
if ( ! isset($image_meta['md_meta_update_complete']) || ! $image_meta['md_meta_update_complete'] ) {
// 1. Copy Title (post_title) to Caption (post_excerpt)
md_copy_title_to_caption( $image_id );
// 2. Read in the IPTC:Title from the file and insert into post_title
md_insert_IPTC_title_as_title( $image_id );
// 3. Read in the IPTC:Keywords from the file and insert into Alt
md_insert_IPTC_keywords_as_alt( $image_id );
// 4. Read in IPTC:Description and put it into description (post_content)
md_insert_IPTC_description_as_description( $image_id );
// 5. Insert the flag to indicate we're done
$image_meta = wp_get_attachment_metadata( $image_id );
$image_meta['md_meta_update_complete'] = true;
update_post_meta($image_id, '_wp_attachment_metadata', $image_meta);
}
}
/*******************************************************************************
By default, the IPTC:Description is used as the title if it's less than 80
characters long, which means that description would be empty. This forces
description to be IPTC:Description no matter how long it is. Overwrites
existing description if present.
@param int $image_id, attachment ID
@return none
*/
function md_insert_IPTC_description_as_description( $image_id ) {
if ( wp_attachment_is_image( $image_id ) ) {
$desc = md_get_iptc_tag( $image_id, 'Description');
md_log( "Desc is $desc" );
if ( $desc ) {
// Update the post_content, which is used for the description
$updated_post = array(
'ID' => $image_id,
'post_content' => $desc,
);
wp_update_post( $updated_post );
}
}
}
/*******************************************************************************
Copies the image title (post_title) WP did on its own (and used IPTC Headline
for) and copies into the caption (post_excerpt). Overwrites existing caption,
but at ingest time it'll be blank so who cares.
@param int $image_id, attachment ID
@return none
*/
function md_copy_title_to_caption( $image_id ) {
if ( wp_attachment_is_image( $image_id ) ) {
$image_obj = get_post( $image_id );
$image_meta = wp_get_attachment_metadata( $image_id );
// First update the image meta
$image_meta['image_meta']['caption'] = $image_obj->post_title;
update_post_meta($image_id, '_wp_attachment_metadata', $image_meta);
// Then update the post_excerpt, which is used for the caption
$updated_post = array(
'ID' => $image_id,
'post_excerpt' => $image_obj->post_title,
);
wp_update_post( $updated_post );
}
}
/*******************************************************************************
Inserts IPTC title as image title (post_title). Overwrites
existing title.
@param int $image_id, attachment ID
@return none
*/
function md_insert_IPTC_title_as_title( $image_id ) {
if ( wp_attachment_is_image( $image_id ) && is_callable( 'iptcparse' ) ) {
$title = '';
$title = md_get_iptc_tag( $image_id, 'Title');
if ( $title ) {
// First update the image meta
$image_meta = wp_get_attachment_metadata( $image_id );
$image_meta['image_meta']['title'] = $title;
update_post_meta($image_id, '_wp_attachment_metadata', $image_meta);
// Then update the post_title
$updated_post = array(
'ID' => $image_id,
'post_title' => $title,
);
wp_update_post( $updated_post );
}
}
}
/*******************************************************************************
Inserts caption and IPTC keywords as comma separated string into Alt Text.
Overwrites existing Alt Text, but at ingest time it'll be blank so who cares.
@param int $image_id, attachment ID
@return none
*/
function md_insert_IPTC_keywords_as_alt( $image_id ) {
if ( wp_attachment_is_image( $image_id ) && is_callable( 'iptcparse' ) ) {
$keywords = md_get_iptc_tag( $image_id, 'Keywords');
$image_meta = wp_get_attachment_metadata( $image_id );
$caption = $image_meta['image_meta']['caption'];
if ( $caption ) { $caption .= "; ";}
if ( $keywords || $caption ) {
update_post_meta($image_id, '_wp_attachment_image_alt', "$caption $keywords");
}
}
}
/*******************************************************************************
Does the actual getting of the IPTC info from the file.
@param int $image_id, attachment ID
@param string $iptc_tag, tag to get, either 'Keywords' or 'Title' or 'Description'
@return string if tag is found and has contents, those contents; empty string otherwise
*/
function md_get_iptc_tag( $image_id, $iptc_tag ) {
$tag = null;
$file = get_attached_file( $image_id );
if ( ! file_exists( $file ) ) { return null; }
// Based on code in image.php in wp core
$size = getimagesize( $file, $info );
if ( ! empty( $info['APP13'] ) && ( 'Title' === $iptc_tag || 'Keywords' === $iptc_tag || 'Description' === $iptc_tag ) ) {
$iptc = iptcparse( $info['APP13'] );
// User var_dump on $iptc to see everything
switch ( $iptc_tag ) {
case 'Title':
if ( ! empty( $iptc['2#005'][0] ) ) {
// string
$tag = trim( $iptc['2#005'][0] );
}
break;
case 'Keywords':
if ( ! empty( $iptc['2#025'][0] ) ) {
// array
$tag = implode( ', ', $iptc['2#025'] );
}
break;
case 'Description':
if ( ! empty( $iptc['2#120'][0] ) ) {
// string
$tag = trim( $iptc['2#120'][0] );
}
break;
default:
}
}
return $tag;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment