Tutorial Details
- Topic: Wordpress
- Difficulty: Advanced
Custom fields in WordPress make it easy to customize your theme in a variety of ways; plus, they are simple to implement for posts and pages. Attachments, on the other hand, take a bit more work to implement, requiring you to read through and decipher core source code in order to make them work. We’ll be walking through the use of a couple undocumented WordPress hooks in this tutorial to make this process much easier.
Preface: About The Hooks
Both these hooks have been around since WordPress 2.5, and are applied in wp-admin/includes/media.php, but remain underused in the community most likely because they’re undocumented in the Codex. Below is where the hooks are applied in the core code, letting us know what will be passed to the functions we add to each hook.
attachment_fields_to_edit
function get_attachment_fields_to_edit($post, $errors = null) {
// ...
$form_fields = apply_filters("attachment_fields_to_edit", $form_fields, $post);
// ...
}
- $form_fields is a special array which will be described in detail in a moment.
- $post is the attachment as an object (attachments are treated as post objects in WordPress).
attachment_fields_to_save
function media_upload_form_handler() {
// ...
$post = apply_filters("attachment_fields_to_save", $post, $attachment);
// ...
}
- $post is the attachment as an array (attachments are treated as post objects in WordPress).
- $attachment is the attachment part of the form $_POST which will include the fields setup through the attachment_fields_to_edit hook.
Note: Be careful in your code, as $post is sent to one function as an object and to the other as an array.
Custom Field Naming Tips
The new fields being added will be saved as post meta, just like the custom fields section of the post/page edit screen. Fields prefixed with an underscore (_my_custom_field) will not be listed in the drop down of available custom fields on the post/page screen; all other existing post meta fields will be listed. We can use this knowledge to hide the fields we’re adding to the media form, since they aren’t relevant for posts/pages.

There is a similar rule to keep in mind when choosing the $form_fields array key to use for your new field. Here, if you use an underscore ($form_fields['_my_custom_field']) your field will be skipped and will not be added to the form.
So in order to show our fields in the media form, but also not list them in the page/post custom fields drop down, we must combine both methods. This will invlove both the edit and save functions we’ll be creating. For the ‘attachment_fields_to_edit‘ hook we’ll set the $form_fields keys up to not have underscore prefixes, and for the ‘attachment_fields_to_save‘ hook we’ll prefix our fields with an underscore before saving them as post meta. This is a workaround worth doing in order to not muddy our users’ interface with unneeded info.
Hook 1: attachment_fields_to_edit
Below is an example of how to add your own custom fields to the attachment form.
/**
* Adding our custom fields to the $form_fields array
*
* @param array $form_fields
* @param object $post
* @return array
*/
function my_image_attachment_fields_to_edit($form_fields, $post) {
// $form_fields is a special array of fields to include in the attachment form
// $post is the attachment record in the database
// $post->post_type == 'attachment'
// (attachments are treated as posts in WordPress)
// add our custom field to the $form_fields array
// input type="text" name/id="attachments[$attachment->ID][custom1]"
$form_fields["custom1"] = array(
"label" => __("Custom Text Field"),
"input" => "text", // this is default if "input" is omitted
"value" => get_post_meta($post->ID, "_custom1", true)
);
// if you will be adding error messages for your field,
// then in order to not overwrite them, as they are pre-attached
// to this array, you would need to set the field up like this:
$form_fields["custom1"]["label"] = __("Custom Text Field");
$form_fields["custom1"]["input"] = "text";
$form_fields["custom1"]["value"] = get_post_meta($post->ID, "_custom1", true);
return $form_fields;
}
// attach our function to the correct hook
add_filter("attachment_fields_to_edit", "my_image_attachment_fields_to_edit", null, 2);
The $form_fields array has several options for including different types of inputs and custom content. I’ve compiled the various methods below with notes and screenshots of how they render in the form.
Text Input
// input type="text"
$form_fields["custom1"]["label"] = __("Custom Text Field");
$form_fields["custom1"]["input"] = "text"; // this is default if "input" is omitted
$form_fields["custom1"]["value"] = get_post_meta($post->ID, "_custom1", true);
Renders in the form as:

Textarea
// textarea
$form_fields["custom2"]["label"] = __("Custom Textarea");
$form_fields["custom2"]["input"] = "textarea";
$form_fields["custom2"]["value"] = get_post_meta($post->ID, "_custom2", true);
Renders in the form as:

Hidden Field
Hidden fields are compiled together and output at the end of the form.
// input type="hidden" // no need for a label $form_fields["custom3"]["input"] = "hidden"; $form_fields["custom3"]["value"] = get_post_meta($post->ID, "_custom3", true);
Other Field Types
If you need an input type other than ‘text’, ‘textarea’, or ‘hidden,’ then use ‘html’ which allows you to pass your own custom content to use for the input element of your choice. When you create your own input html, it’s important to set the ‘name’ attribute on the element correctly, in order for the field to be passed to our save function later. You want something like this: name = "attachments[$post->ID][my_custom_key]" .
$form_fields["custom4"]["label"] = __("Custom Select");
$form_fields["custom4"]["input"] = "html";
$form_fields["custom4"]["html"] = "
<select name='attachments[{$post->ID}][custom4]' id='attachments[{$post->ID}][custom4]'>
<option value='1'>Option 1</option>
<option value='2'>Option 2</option>
<option value='3'>Option 3</option>
</select>";
// another example
$form_fields["custom5"]["label"] = __("Custom Checkbox");
$form_fields["custom5"]["input"] = "html";
$form_fields["custom5"]["html"] = "the html output goes here, like a checkbox:
<input type='checkbox' value='1'
name='attachments[{$post->ID}][custom5]'
id='attachments[{$post->ID}][custom5]' />";
Renders in the form as:

Special Attributes
There are several special attributes you can add to your custom fields to enhance them.
helps – This attribute adds a help string to your custom field.
$form_fields["custom6"]["label"] = __("Custom Field with Helpful Text");
$form_fields["custom6"]["value"] = get_post_meta($post->ID, "_custom6", true);
$form_fields["custom6"]["helps"] = "Put helpful text here.";
This renders in the form as:

required – This attribute will mark the field as required; but it is only a visual reference. We’ll have to write code later in the save function to enforce it.
$form_fields["custom7"]["label"] = __("Required Field");
$form_fields["custom7"]["value"] = get_post_meta($post->ID, "_custom7", true);
$form_fields["custom7"]["required"] = TRUE; // default is FALSE
Renders in the form as:

extra_rows – This attribute lets you add an array of rows right after your custom field. The markup for each array item is shown below: the array key will become the class of the td, and the value is the content:
// extra_rows markup:
// <tr>
// <td></td>
// <td class="{arrayItemKey}">{arrayItemValue}</td>
// </tr>
$form_fields["custom8"]["label"] = __("Custom Field with Extra Rows");
$form_fields["custom8"]["value"] = get_post_meta($post->ID, "_custom8", true);
// extra_rows must be an associative array $cssClass => $content
$form_fields["custom8"]["extra_rows"] = array(
"cssClass1" => "If you need a few rows after your field...",
"cssClass2" => "...to maybe explain something or add some imagery?
<img src='".get_bloginfo("wpurl")."/wp-admin/images/align-left.png' />
<img src='".get_bloginfo("wpurl")."/wp-admin/images/align-center.png' />
<img src='".get_bloginfo("wpurl")."/wp-admin/images/align-right.png' />",
);
Renders in the form as:

tr – While extra_rows only lets you add table cells directly under your custom field’s input element, this attribute lets you create entire rows.
The table we’re adding a row to has two columns, so keep that in mind when using this method. And this doesn’t have to be a form field, you could just add a row that explains the next few fields, add all of your fields manually, or something else entirely.
$form_fields["custom8"]["tr"] = " <tr id='MySpecialRow'> <td colspan='2' style='background:#000;color:#fff;'> Can do whatever you want, style it, add some fields, display a table of data...sky's the limit </td> </tr>";
Renders in the form as:

Hook 2: attachment_fields_to_save
Saving your custom fields is a much simpler process than adding them to the form; just check if your field is set and update its value as post meta. Remeber to prefix your field with an underscore when saving to hide it on the post/page edit screen.
/**
* @param array $post
* @param array $attachment
* @return array
*/
function my_image_attachment_fields_to_save($post, $attachment) {
// $attachment part of the form $_POST ($_POST[attachments][postID])
// $post attachments wp post array - will be saved after returned
// $post['post_type'] == 'attachment'
if( isset($attachment['my_field']) ){
// update_post_meta(postID, meta_key, meta_value);
update_post_meta($post['ID'], '_my_field', $attachment['my_field']);
}
return $post;
}
You can also add errors here that will automatically be displayed below your field in the form. The $post['errors'] array gets merged with the $form_fields array before being sent through the attachment_fields_to_edit hook.
/**
* @param array $post
* @param array $attachment
* @return array
*/
function my_image_attachment_fields_to_save($post, $attachment) {
if( isset($attachment['my_field']) ){
if( trim($attachment['my_field']) == '' ){
// adding our custom error
$post['errors']['my_field']['errors'][] = __('Error text here.');
}else{
update_post_meta($post['ID'], 'my_field', $attachment['my_field']);
}
}
return $post;
}
Note Regarding Custom Errors: There are a couple long standing bugs in WordPress (as of version 3.0-RC3) that have to do with the display of custom errors.
- One will prevent your custom error messages from showing up on the single media edit page.
-
The other bug is in the modal popup for media items used on the post/page edit screen. The errors do display
here, it’s just the problem of initially seeing them. After saving you’re automatically switched to the
‘Gallery’ tab where there’s a minimized list of media items. If you click on ‘show’ to open your new item,
you’ll see your error messages in the form. The problem is that if there are errors, that items form is supposed to
be open by default. There’s a bug in the css where the class ‘startopen’ (which is present on the item if
there are errors to show) has the value of ‘display:none’ in a few places in the core stylesheets.
I have submitted patches for both of these issues (#13810 & #13838), and have been told they should be reviewed and included by version 3.1. So for now, don’t rely on your error messages too much, just be glad you know how to work with them for when they become more useful in the near future.
Other Ideas
You may want to include some of your fields on only audio attachments, or just images attached to the front page. To further customize your attachment forms, just wrap your special fields in distinguishing statements for both the edit and save functions.
// for audio files
if( substr($post->post_mime_type, 0, 5) == 'audio' ){
// add your custom fields for audio files
}
// OR for images on a specific page
$page_id = 5; // set the id to whatever page you want these applied to
if( $post->post_parent == $page_id && substr($post->post_mime_type, 0, 5) == 'image' ){
// add your image specific custom fields for this particular page
}
If you think of any clever ways to use custom fields with attachments, share it with us in the comments!

Just what I was looking. Many thanks. Custom fields + wordpress 3′s custom post types = endless admin page customization!
WordPress is has improved so much over the years. Tutorials like this are the best way to explain the true power behind it.
this is Great!
Thank you, wordpress keeps getting better and better!
I love learning more about WordPress everyday and you’re making it easy to do that. I’ve been using custom fields forever but this adds to what I now know about them.
This is awesome. I really had no idea we could hook into attachments this way.
I am sure artists would love to have all kinds of extra image fields like the medium used, cost for the artwork, where it can be seen on display, etc.
Thanks, glad you enjoyed it! And good example, I’m sure people will find a ton of useful ways to use custom fields on their attachments: Art, Music, Video, Product Uploads, etc. I hope we’ll see more plugins that take advantage of this, too.
Excellent tutorial, will add more extra fields to wordpress post types.
This seems like it could be a great way to make using WordPress even easier for my clients. Custom fields are great already, but they can require a little hand-holding for clients who really aren’t techno-savvy.
Thanks for the thorough documentation. I wonder what other gems are missing from the codex?
When I had found these hooks, and noticed how old they were, I thought the same thing…what other gems are there hidden only in the source code.
Hi!
i’ve just try it … without results …
Does it mean that when i put the right snippets into my functions.php the custom form fields (like in your snapshots) will appear in my post-edit UI?
greetz
mil
Hey Mil, these hooks deal with uploaded media (images, video, audio, etc.), they won’t show up on the post/page edit screen. So after including the code in your functions.php, go into your media library to edit an item, the new fields show up in that form.
Hi Andy!
I’ve got it … thanks a lot!!!
Great tutorial on WP customization.
do you know of a way to enable those custom panels AFTER the user chose a category? some of the custom fields are needed to certain category and other to another category, so what would be best the best way to not clutter the ui with all the options (without creating custom post types)?
Sure! Just check if the attachment’s parent post is in the category you want, and only add/save your fields if it is. Similar to the ‘Other Ideas’ at the end of the post.
Here’s an example (if code blocks work in the comments):
// $post->post_parent = the attachment's associated page ID
$category = 5;
if ( in_category( $category, $post->post_parent ) ) {
// add your category specific fields here
}
thanks, but what I meant is say you do a custom write panel with field_A and field_B and you only need those to be present (viewable and visible to the user/content submitter) ONLY after he chooses which category to insert the post to..
thanks again!
weird D: i can’t recover the data from this custom field, how to do that?
isn’t using get_post_meta( $post->ID, ‘my_field or _custom1′, true ); ?
Great thanks, question: what about the ability to add ‘browse button’ to be able to upload an image directly in the custom filed with out going back to the media library and copy the url?
This is incredibly helpful, I’d been using magic-fields to do stuff like this prior but I’d much rather build this functionality into the theme.
Glad I could help! Sometimes plugins do over complicate things, it’s nice to be able to hand-code a simple solution when you can.
Thanks for posting this, I have actually been spending the last month trying to figure out how to do this. I’m in the process of making a plug-in that lets you add form fields from the admin section (instead of writing the code).
Couple of self-notes, I’ll see if I can integrate it with the post_meta, at the moment I was thinking about creating a separate database table, but including it with the post_meta might be better, IDK, one thing to consider is what happens when an admin removes a field or uninstalls the plug-in.
The only thing I need to do I think is make a custom shortcode that iterates the data into the template. As of now, I don’t think WordPress’s gallery feature paginates results, so that will need some tweaking.
@Randy, exactly. I have an artist that wants to save print size/medium type/price etc. along with the images, I’m sure there’s other uses too.
Great tutorial on WP customization. Even it very helpful to me because i m new to WP..
I have searched the entire internet for code that would allow you to set custom fields as required, and at save throw an error if they were empty. Or for that matter custom validation. I just don’t think wordpress allows it.
I’d love to see a tutorial for creating custom fields that are required. And if a field is empty, it would not save the post and it would change the message variable in the redirect to a custom message letting you know it was not saved.
Maybe I’m missing something, but I can’t get the checkbox ‘save’ to work. I can display it fine, using the code above, but when i check it and save the attachment, the checkbox is always unchecked.
Is there something extra I need to do?
still can’t recover the data from this custom field, and when I click on save they don’t save :\
what i’m doing wrong?
Be sure that you’re passing the attachment-ID when you call get_post_meta, not the regular post-ID.
Hope this helps.
aahm, but, how to get the attachment-ID?
isn’t $attachmend->ID like $post->ID
Yea, excellent tutorial. I knew this could be done.
However, i think your tutorial is missing something. I’ve set it up just like you have it, but you aren’t showing us how to save and recover the data! you’ve got this “my_image_attachment_fields_to_save”, but it doesn’t work. and i’m assuming the ‘my_field’ should map to one of the ‘custom1′ form fields above? it would have been nice to throw in a complete code block to look at.
Yea, i’ve followed this tutorial exactly and it won’t save the custom field. i think what you left out is adding the save filter after the “my_image_attachment_fields_to_save” bit:
add_filter(“attachment_fields_to_save”, “my_image_attachment_fields_to_save”, null, 2);
Also, you are not providing a way to save the checkboxes or dropdowns!!! come on, dude. i finally got the text field working, but you don’t provide any way to save a checkbox. i’ll try and put that in to help everybody out if i can figure it out. thanks.
Yeah, I have the same issue. I can’t seem to find the right way to save the data to the database. Any help on this would be great, as it seems nobody else have covered this topic.
Thanks
Vayu
Sorry to everyone having trouble saving their fields! Yes, I accidentally left a line out after the save function ‘my_image_attachment_fields_to_save($post, $attachment)’ that hooks that in. Apologies!
add_filter(“attachment_fields_to_save”, “my_image_attachment_fields_to_save”, null, 2);
I’ll try my best to get a couple examples up for everyone by tomorrow in regards to the manually coded fields like checkboxes and selects. I’m in the middle of moving at the moment though, so bear with me while I post them with my phone. Thanks for the heads up everyone!
Thanks Andy.
I also tried this, but without any luck. Its still not saving to the database with this add_filter.
Here is the code I have used to test with:
add_filter(“attachment_fields_to_edit”, “my_image_attachment_fields_to_edit”, null, 2);
add_filter(“attachment_fields_to_save”, “my_image_attachment_fields_to_save”, null, 2);
function my_image_attachment_fields_to_edit($form_fields, $post) {
$form_fields["custom6"]["label"] = __(“Custom Field with Helpful Text”);
$form_fields["custom6"]["value"] = get_post_meta($post->ID, “_custom6″, true);
$form_fields["custom6"]["helps"] = “Put helpful text here.”;
return $form_fields;
}
function my_image_attachment_fields_to_save($post, $attachment) {
if( isset($attachment['add_class']) ){
update_post_meta($post['ID'], ‘_add_class’, $attachment['add_class']);
}
return $post;
}
Hey Vayu, tweaked your code to make it work. The variable names in the edit/save were different. I’ll try to get the examples up during lunch today, yesterday I was moving boxes from the time I got home until I went to sleep.
add_filter("attachment_fields_to_edit","my_image_attachment_fields_to_edit",null,2);
add_filter("attachment_fields_to_save","my_image_attachment_fields_to_save",null,2);
function my_image_attachment_fields_to_edit($form_fields,$post){
$form_fields["custom6"]["label"]=__("Custom Field with Helpful Text");
$form_fields["custom6"]["value"]=get_post_meta($post->ID,"_custom6",true);
$form_fields["custom6"]["helps"]="Put helpful text here.";
return $form_fields;
}
function my_image_attachment_fields_to_save($post,$attachment){
if(isset($attachment['custom6'])){
update_post_meta($post['ID'],'_custom6',$attachment['custom6']);
}
return $post;
}
Hi Andy.
Well, that was embarrassing! Nevertheless, thank you very much!
I too, look forward to your forthcoming other examples. :-)
Vayu
Don’t know what happened to all my spaces…? Let’s try that code block again:
add_filter("attachment_fields_to_edit", "my_image_attachment_fields_to_edit", null, 2);
add_filter("attachment_fields_to_save", "my_image_attachment_fields_to_save", null, 2);
function my_image_attachment_fields_to_edit($form_fields, $post) {
$form_fields["custom6"]["label"] = __("Custom Field with Helpful Text");
$form_fields["custom6"]["value"] = get_post_meta($post->ID, "_custom6", true);
$form_fields["custom6"]["helps"] = "Put helpful text here.";
return $form_fields;
}
function my_image_attachment_fields_to_save($post, $attachment) {
if( isset($attachment['custom6']) ) {
update_post_meta($post['ID'], '_custom6', $attachment['custom6']);
}
return $post;
}
Excited to see those examples with text fields, selects and checkboxes etc….
I’ve put some full code samples on my site to better show how to setup select boxes and check boxes. I’ll add to that file if anyone has any requests for other examples, let me know!
http://www.andyblackwell.com/code/creating-custom-fields-for-attachments-in-wordpress-examples.txt
Hi Andy.
Thanks for the extra examples. Much appreciated! :-)
I don’t know if it is just my settup, but in my case it is not possible to deselect the checkbox again. So, once the checkbox is clicked and saved, it is not possible to deselect and save it again. It doesn’t seem to save that. Anyone else get that?
Hey Vayu, I just updated the file. It needs a blank valued hidden field before the checkbox to ‘delete’ the value whenever the checkbox is unchecked. Thanks for catching that!
how can I use multiple checkbox? I have to get the author list and display to the User checkbox to assign the authors to media.
Sorry my english…
I’m a bit confused now.
http://www.andyblackwell.com/code/creating-custom-fields-for-attachments-in-wordpress-examples.txt
Is this for creating custom fields inside a post?
I was hoping there would be an example on how to use custom fields. Not select boxes and check boxes when uploading media.
Sorry Kyle, could you elaborate? This tutorial was about using custom fields with uploaded media. Are you looking for actual usage examples of this, or just examples of using normal custom fields with posts/pages? If it’s usage examples you want you’re in luck, since I’ve started a followup tutorial to show several examples of how useful they can be in certain situations.
Normal custom fields in post pages. I think I’m asking too much though. :P
I know WordPress has it’s limitations, and when I read your tutorial above I got excited that there may be a way to make regular custom fields within posts/pages required and show error messages. Error messages that are attached to the message variable in the url string if possible.
I know there are a ton of plugins out there, like custom write pages, and more fields….etc… but I was hoping you might have the secret to the holy grail as to how to get this done using core features.
Anyway I think this is something we all dream of but isn’t possible yet with WordPress.
I’m pretty new to WordPress, but not new to coding, so I’ve been on this quest to learn what my limitations with WordPress are.
@Andy Still can’t recover the data on posts, how to do that? D: there’s another way instead get_post_meta?
I’m also interested in seeing how to get the data out and displayed on a page.
Thanks,
J.
Interesting article, Andy…just on time as I was looking at media (image) fields tweaks. Particularly, I want to use the caption field in the following scenario:
* I’m using a special post template for some posts. This template make a call for a special post thumbnail template in order to generate a special image thumb within the special post template.
“Thumbnail” and “Thumbnail Alt” from the code below are custom fields within the post. I’m using “Thumbnail” custom field to indicate the image URL (the image is in the media gallery and the caption field is filled in).
Things is, I want to use the caption field in order to display the image’s source & copyright. My coding skills are minimal unfortunately and seems I’m missing something when trying to write the correct code to do just that…
That’s the code for the special post thumbnail.php:
ID, ‘Thumbnail’, $single = true);
// check for thumbnail alt text
$thumb_alt = get_post_meta($post->ID, ‘Thumbnail Alt’, $single = true);
?>
<img src="” width=”400px” height=”200px” alt=”" />
What should I add to display the caption for the image under the image in the thumbnail div?? I saw in WP’s media.php that the code used to construct the html for using caption to display is
html = ‘[caption id="" align="'+t.align+'" width="'+t.width+'" caption="'+caption+'"]‘+html+’[/caption]‘;
If caption can be retrieved like this (not sure if correct but anyway; I know wp_attachement_image_alt exists so I assumed a similar variable for caption):
$caption = get_post_meta($post->ID, ‘_wp_attachment_image_caption’, true);
what about the caption ID??
html = ‘[caption id="" align="'+t.align+'" width="'+t.width+'" caption="'+caption+'"]‘+html+’[/caption]‘;
This is nice =)
Great tut, would this work for attaching any file? For example I have classipress and the one thing lacking is the ability for the user to add an attachment, say a pdf, jpeg or whatever they want when replying to a classified advert.
Thanks so much for this incredible nugget, Andy! I was having a terrible time getting the values of each field to save until I switched the filters from double quotes to single quotes. I’m not sure why, but it may be helpful to someone else.
From:
add_filter(“attachment_fields_to_edit”, “my_image_attachment_fields_to_edit”, null, 2);
add_filter(“attachment_fields_to_save”, “my_image_attachment_fields_to_save”, null, 2);
To:
add_filter(‘attachment_fields_to_edit’, ‘my_image_attachment_fields_to_edit’, null, 2);
add_filter(‘attachment_fields_to_save’, ‘my_image_attachment_fields_to_save’, null, 2);
Andy you’re the shit!!!!! Thank you so much for this awesome tutorial!
I can’t seem to find the right way to save the data to the database. Any help on this would be great, as it seems nobody else have covered this topic.
Thanks
great tutorial, it works great but how can i display the new metadatas in my single.php
Great tutorial….it saved my day!!! I was just finding out how to add custom fields to attachments. I had used the two hooks ‘attachment_fields_to_edit’ and ‘attachment_fields_to_save’ earlier as well. But the idea of underscore to hide the meta field from edit post/page panel was new for me, that I was trying to achieve. As well the tutorial is so well written, totally understandable.
Thanks a million.
Ok then :( nobody answered my question about how to retrieve the custom fields :\
like that:
a custom field named ‘featured’ and one named ‘middle’(that one will appear in the middle of the post)
ok
ahm, i want to retrieve the image checked as featured on my homepage, and the middle in the middle of the post in the single, or top or i don’t know, any place :)
but, without inserting in the post
D: how to?
Hey Pedro, to get the attachments like you described, use this code: (I guessed at the value you set for the fields you mentioned)
$featured_image_attachments = query_posts(‘post_type=attachment&post_mime_type=image&meta_key=featured&meta_value=1′);
$middle_image_attachments = query_posts(‘post_type=attachment&post_mime_type=image&meta_key=middle&meta_value=1′);
http://codex.wordpress.org/Function_Reference/query_posts#Post_.26_Page_Parameters
http://codex.wordpress.org/Function_Reference/query_posts#Custom_Field_Parameters
To get the meta of attachments on a post, use:
// $post – the current post object
$post_attachments = query_posts(‘post_type=attachment&post_mime_type=image&post_parent=’.$post->ID);
foreach($post_attachments as $post_attachment){
$attachment_meta = get_post_custom($post_attachment->ID);
// now you have the custom fields
$attachment_meta['_my_custom_field'];
}
Andy, thanks so much! This is has been really helpful. One question: should this data be accessible elsewhere? For example, I’m using your ‘selectbox’ example that was in your text file, which creates mySelectBox values. I am then, in another plugin, trying to call that value, but I don’t think it’s grabbing the value. I’m trying like this:
// get attachments
$attachments = wp_cache_get( ‘attachments’, ‘eg-attachments’ );
if ($attachments === FALSE || !isset($attachments[$id])) {
$attachment_list = get_posts( array(‘post_parent’ => $id,
‘numberposts’ => -1,
‘post_type’ => ‘attachment’,
‘orderby’ => $order_by,
‘order’ => $order
)
);
if ($attachment_list !== FALSE && sizeof($attachment_list)>0) {
$attachments[$id] = $attachment_list;
wp_cache_set(‘attachments’, $attachments, ‘eg-attachments’, $this->cacheexpiration);
}
}
But this doesn’t seem to grab the the mySelectBox value. Is this because the value doesn’t get included using wp_cache_get() ?
The cache won’t store the meta because it’s not part of the attachment object, but all you need is the attachment ID to get it.
$attachment_meta = get_post_custom($attachment->ID);You could probably modify your caching to also cache the meta values too, if you wanted to optimize. You would have to loop through the attachments, getting the meta for each, and caching what’s returned. Test it, but this might work.
if ($attachment_list !== FALSE && sizeof($attachment_list)>0) {foreach($attachment_list as $i => $attachment){
// add and set a 'meta' property to the object to get the values from later
$attachment_list[$i]->meta = get_post_custom($attachment->ID);
}
$attachments[$id] = $attachment_list;
wp_cache_set(‘attachments’, $attachments, ‘eg-attachments’, $this->cacheexpiration);
}
Hope that helps!
Thanks, Andy. I tried this, without success. I used your second code block above. I then changed this code to pull the meta value to replace %CAPTION% (the plugin code I’m using).
case ‘custom’:
$tmp = html_entity_decode (stripslashes($format));
$tmp = preg_replace(“/%URL%/”, ($hidepost_hide_link==1?’#':$url),$tmp);
//A direct link to some files may be necessary – some programs don’t work when the mimetype is not set correctly
$tmp = preg_replace(“/%TITLE%/”, $attachment_title,$tmp);
$tmp = preg_replace(“/%CAPTION%/”, $attachment->meta,$tmp);
//For use with stylesheets
$output .= $tmp;
Feel free to email me directly. I’m willing to pay you for your time to help me understand/fix this!
$attachment->metawill be an array of all the custom variables for that attachment, so you’ll have to access whatever key you saved your value to, like:$attachment->meta['_mySelectBox']Just to make sure, did you see the comments regarding the missing line in the tutorial as well, that hooks in the function to save the custom meta?
add_filter("attachment_fields_to_save","my_image_attachment_fields_to_save",null,2);Yeah, I used your .txt file as a guide, and it has:
add_filter(“attachment_fields_to_edit”, “attachment_selectbox_edit”, null, 2);
And yep, it’s definitely saving the value because it’s remembering different values for different posts when I go back to the pages later. Obviously I’m doing something else wrong because it’s still not inserting the value into my HTML output.
Good. Did you try changing the place where you were using meta yet:
$tmp = preg_replace(“/%CAPTION%/”, $attachment->meta,$tmp);to:
$tmp = preg_replace(“/%CAPTION%/”, $attachment->meta['_mySelectBox'],$tmp);Or whatever key you chose if not ‘_mySelectBox’
It also has
add_filter(“attachment_fields_to_save”, “attachment_selectbox_save”, null, 2);
Just copied the wrong line. So yeah, I’ve played around with the code some more, and it’s almost like the value isn’t a string or it’s in some other format that simply isn’t translating over when I use the code:
$attachment->meta['_mySelectBox']
It completely blows up the HTML output. (I have the value of the select box as both the text of an li element and assigning a class attribute of the same value to that li element.) When I use this code, the li element doesn’t even turn up in the markup. Just the surrounding tags. When I use the original post_excerpt value and put the text into that text box, it returns the value and works as expected. There’s just something that isn’t quite right. Thanks for your help. Again, feel free to email privately if you have time to help further. I have to finish this tomorrow.
-B
What’s the value supposed to be? It probably needs to be escaped if your using it as an html attribute value, and could be why it’s breaking the html. Can you ‘view source’ to see what it’s actually printing out?
You can use the WordPress escaping functions if that’s the case:
echo esc_attr( $text );echo esc_html( $text );
Or just not use the value for the html attribute to see if it fixes the issue.
Here are the values from media.php:
// select options: you could code these manually or get it from a database
$select_options = array(
“” => “None”,
“bids” => “Bids”,
“comps” => “Comps”,
);
The code to add the attachment meta to array:
// get attachments
$attachments = wp_cache_get( ‘attachments’, ‘eg-attachments’ );
if ($attachments === FALSE || !isset($attachments[$id])) {
$attachment_list = get_posts( array(‘post_parent’ => $id,
‘numberposts’ => -1,
‘post_type’ => ‘attachment’,
‘orderby’ => $order_by,
‘order’ => $order
)
);
if ($attachment_list !== FALSE && sizeof($attachment_list)>0) {
foreach($attachment_list as $i => $attachment){
// add and set a ‘meta’ property to the object to get the values from later
$attachment_list[$i]->meta = get_post_custom($attachment->ID);
}
$attachments[$id] = $attachment_list;
wp_cache_set(‘attachments’, $attachments, ‘eg-attachments’, $this->cacheexpiration);
}
}
The code to replace the %CAPTION% instances with the value of _mySelectBox:
case ‘custom’:
$tmp = html_entity_decode (stripslashes($format));
$tmp = preg_replace(“/%URL%/”, ($hidepost_hide_link==1?’#':$url),$tmp);
//A direct link to some files may be necessary – some programs don’t work when the mimetype is not set correctly
$tmp = preg_replace(“/%GUID%/”, $attachment->guid,$tmp);
$tmp = preg_replace(“/%ICONURL%/”, $this->get_icon($attachment->ID, $attachment, $size),$tmp);
$tmp = preg_replace(“/%TITLE%/”, $attachment_title,$tmp);
$tmp = preg_replace(“/%CAPTION%/”, $attachment->meta['_mySelectBox'],$tmp);
$tmp = preg_replace(“/%ATTID%/”, $attachment->ID,$tmp); //For use with stylesheets
$output .= $tmp;
In the template for the plugin, here is how %CAPTION% is being replaced (the URL is pulling in fine since it isn’t affected by this custom attachment value):
%CAPTION%
And finally, when I set the value to “bids” in the Media Library and save it (it is saving the value if I log out and come back in and check), and then look at the output on the HTML page, I get:
Thoughts?
Weird, it removed some code. Basically lines were:
CAPTION
CAPTION obviously has % on either side…just removed for the sake of posting here.
Output is just the UL item, with no LI inside it at all.
Oh man, so close! You provided everything but how to actually output these fields anywhere. Can you help a girl out? I’ve tried a few iterations of the usual method of getting custom fields. Nada, except at one point it output the word “ARRAY” like that.
So I tried, and read through the comments below, but I’m really stumped. Thanks in advance to anyone who helps me out here. ;)
Sorry, I forgot to add that what I’m trying to do is take the regular input box field this tutorial added and output its content as a string that will go in a caption box. But I’d also like to try using the select box to offer different styles that would be applied to an image. Thanks.
To get the meta of attachments on a post, use this code:
// $post – the current post object// get the post's attachments
$post_attachments = query_posts(‘post_type=attachment&post_mime_type=image&post_parent=’.$post->ID);
// loop through all the attachments and get your custom fields
foreach($post_attachments as $post_attachment){
$attachment_meta = get_post_custom($post_attachment->ID);
// now you have the custom fields, and can do stuff with them now
echo $attachment_meta['_my_custom_field'];
if( !empty($attachment_meta['_another_field']) && $attachment_meta['_another_field'] === TRUE ){
echo "<p>This shows if 'another_field' is TRUE</p>";
}
// or debug what you've got
echo '<pre>';
echo 'Custom Data for Attachment ID=' . $post_attachment->ID . "\n";
var_dump($attachment_meta);
echo "\n\n";
echo '</pre>';
}
Hope that helps, I really need to write a follow-up turorial with several working examples.
yah..that’s great, i have made it at last
Its cool! Could anybody show it in action?
Really i never came across such a perfectly written post on custom fields … thanks for sharing .
Thanks for this amazing tutorial !
I was wonderning, now we know how to add custom fields to attachments, but is it possible to remove some of the existing ones ?
Would it be possible to add a custom button that adds a short tag to the ‘File url’ so you could insert that directly into a post?
if it works already in wp 3.1, I added the source code of example in the administration panel but I do not see results for a test I added die () in the function named my_image_attachment_fields_to_edit but nothing happened. I added the entire example code in Function.php
Hey Mario, try putting these examples in your functions.php file, make sure it is `functions.php`, plural with an ‘s’
http://www.andyblackwell.com/code/creating-custom-fields-for-attachments-in-wordpress-examples.txt
Of course I use the functions.php file. I create own post types, and they work without a problem, but unfortunately not custom field, I checked and it seems to me that attachment_fields_to_edit hook is not invoked when generating a form.
All right, I slammed my face on this one for a bit and I swear there’s something my eyes are apparently blind to.
I get the checkbox displayed on the media panel, but…
as soon as the DR_image_attachment_fields_to_save method is enabled, bad things happen:
1~ the checkbox is displayed as unchecked even for media where I did check it
2~ the value of the checkbox doesn’t seem to be saved to the database anyway
3~ Caption and Description for the media get lost (<– now *that* is weird, isn't it?)
If you can take a look and spot my error it'll help my tremendously. Thank you in advance.
From my functions.php (developing a theme for WP 3.1)
/* DR_attachment_fields_to_edit:
————————————————– */
if ( ! function_exists( ‘DR_attachment_fields_to_edit’ ) ):
function DR_attachment_fields_to_edit($form_fields, $post) {
// get the current value of our custom field
$current_value = get_post_meta($post->ID, ‘_mycbox’, true);
// if this value is the current_value we’ll mark it checked
$checked = ($current_value == ‘picked’) ? ‘ checked=”checked” ‘ : ”;
// update 2010-08-05 @ 5:10pm CDT: hidden field takes over if the checkbox is unchecked, in essence deleting the value
$myCheckBoxHtml = ‘
ID.’][mycbox]” value=”" />
ID.’][mycbox]” id=”attachments['.$post->ID.'][mycbox]” value=”picked” ‘.$checked.’ />
‘;
$form_fields[mycbox]["label"] = DR_Label(‘Attachments Properties: In Gallery (Label)’);
$form_fields[mycbox]["input"] = “html”;
$form_fields[mycbox]["html"] = $myCheckBoxHtml;
return $form_fields;
}
endif;
add_filter(‘attachment_fields_to_edit’, ‘DR_attachment_fields_to_edit’, null, 2);
/* DR_image_attachment_fields_to_save:
————————————————– */
if ( ! function_exists( ‘DR_image_attachment_fields_to_save’ ) ):
function DR_image_attachment_fields_to_save($form_fields, $post) {
if( isset($attachment['mycbox']) ){
update_post_meta($post['ID'], ‘_mycbox’, $attachment['mycbox']);
}
return $post;
}
endif;
add_filter(‘attachment_fields_to_save’, ‘DR_image_attachment_fields_to_save’, null, 2);
I found it?
function DR_image_attachment_fields_to_save($form_fields, $post) {
should have been
function DR_image_attachment_fields_to_save($post, $attachment) {
Thanks – we now return you to your regularly scheduled universe
HA! Glad you found and fixed the problem so fast :) I hope it’s working out well for you