When building a UI for adding meta data to a post in WordPress it’s always best to stick to the WordPress styling as much as possible. So, if you’re adding an image upload field to a post, it’s often a good idea to use a known UI element such as the Featured Image meta box. This especially useful if you are asking for a ‘secondary’ featured image – such as one that could be used as a post header image, while keeping the default featured image separate for blog listings, etc.
I did exactly that in a recent project where the posts needed a landscape listing image to be displayed in blog listings while the featured image was reserved for social sharing and viewing inside the single post content.
In order to achieve this I needed to add a custom meta box (with markup copied from the core Featured Image box) along with some Javascript to handle the media upload and general on page functions. You will find all of the code for this below and it works 100% correctly as is:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
add_action( 'add_meta_boxes', 'listing_image_add_metabox' ); | |
function listing_image_add_metabox () { | |
add_meta_box( 'listingimagediv', __( 'Listing Image', 'text-domain' ), 'listing_image_metabox', 'post', 'side', 'low'); | |
} | |
function listing_image_metabox ( $post ) { | |
global $content_width, $_wp_additional_image_sizes; | |
$image_id = get_post_meta( $post->ID, '_listing_image_id', true ); | |
$old_content_width = $content_width; | |
$content_width = 254; | |
if ( $image_id && get_post( $image_id ) ) { | |
if ( ! isset( $_wp_additional_image_sizes['post-thumbnail'] ) ) { | |
$thumbnail_html = wp_get_attachment_image( $image_id, array( $content_width, $content_width ) ); | |
} else { | |
$thumbnail_html = wp_get_attachment_image( $image_id, 'post-thumbnail' ); | |
} | |
if ( ! empty( $thumbnail_html ) ) { | |
$content = $thumbnail_html; | |
$content .= '<p class="hide-if-no-js"><a href="javascript:;" id="remove_listing_image_button" >' . esc_html__( 'Remove listing image', 'text-domain' ) . '</a></p>'; | |
$content .= '<input type="hidden" id="upload_listing_image" name="_listing_cover_image" value="' . esc_attr( $image_id ) . '" />'; | |
} | |
$content_width = $old_content_width; | |
} else { | |
$content = '<img src="" style="width:' . esc_attr( $content_width ) . 'px;height:auto;border:0;display:none;" />'; | |
$content .= '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set listing image', 'text-domain' ) . '" href="javascript:;" id="upload_listing_image_button" id="set-listing-image" data-uploader_title="' . esc_attr__( 'Choose an image', 'text-domain' ) . '" data-uploader_button_text="' . esc_attr__( 'Set listing image', 'text-domain' ) . '">' . esc_html__( 'Set listing image', 'text-domain' ) . '</a></p>'; | |
$content .= '<input type="hidden" id="upload_listing_image" name="_listing_cover_image" value="" />'; | |
} | |
echo $content; | |
} | |
add_action( 'save_post', 'listing_image_save', 10, 1 ); | |
function listing_image_save ( $post_id ) { | |
if( isset( $_POST['_listing_cover_image'] ) ) { | |
$image_id = (int) $_POST['_listing_cover_image']; | |
update_post_meta( $post_id, '_listing_image_id', $image_id ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jQuery(document).ready(function($) { | |
// Uploading files | |
var file_frame; | |
jQuery.fn.upload_listing_image = function( button ) { | |
var button_id = button.attr('id'); | |
var field_id = button_id.replace( '_button', '' ); | |
// If the media frame already exists, reopen it. | |
if ( file_frame ) { | |
file_frame.open(); | |
return; | |
} | |
// Create the media frame. | |
file_frame = wp.media.frames.file_frame = wp.media({ | |
title: jQuery( this ).data( 'uploader_title' ), | |
button: { | |
text: jQuery( this ).data( 'uploader_button_text' ), | |
}, | |
multiple: false | |
}); | |
// When an image is selected, run a callback. | |
file_frame.on( 'select', function() { | |
var attachment = file_frame.state().get('selection').first().toJSON(); | |
jQuery("#"+field_id).val(attachment.id); | |
jQuery("#listingimagediv img").attr('src',attachment.url); | |
jQuery( '#listingimagediv img' ).show(); | |
jQuery( '#' + button_id ).attr( 'id', 'remove_listing_image_button' ); | |
jQuery( '#remove_listing_image_button' ).text( 'Remove listing image' ); | |
}); | |
// Finally, open the modal | |
file_frame.open(); | |
}; | |
jQuery('#listingimagediv').on( 'click', '#upload_listing_image_button', function( event ) { | |
event.preventDefault(); | |
jQuery.fn.upload_listing_image( jQuery(this) ); | |
}); | |
jQuery('#listingimagediv').on( 'click', '#remove_listing_image_button', function( event ) { | |
event.preventDefault(); | |
jQuery( '#upload_listing_image' ).val( '' ); | |
jQuery( '#listingimagediv img' ).attr( 'src', '' ); | |
jQuery( '#listingimagediv img' ).hide(); | |
jQuery( this ).attr( 'id', 'upload_listing_image_button' ); | |
jQuery( '#upload_listing_image_button' ).text( 'Set listing image' ); | |
}); | |
}); |
The PHP code simply needs to be added to your theme’s functions.php
file (or better yet, a custom plugin) and the Javascript needs to be loaded on the post edit screen and you’ll be good to go with a new meta box that looks and works exactly the same as the default Featured Image box.
Thanks for the wonderful code Hugh! I tried to use it in one plugin I am developing. One thing I am not getting. If I set a listing image and click on remove image, without updating the post, it is not working as the original featured image behavior of WordPress Posts. Please suggest.
add this “jQuery(“#listingimagediv img”).attr(‘srcset’,attachment.url);” When an image is selected, run a callback.
Thanks for this!
Just a minor correction:
file_frame = wp.media.frames.file_frame = wp.media({
title: jQuery( this ).data( ‘uploader_title’ ),
button: {
text: jQuery( this ).data( ‘uploader_button_text’ ),
…
should be:
file_frame = wp.media.frames.file_frame = wp.media({
title: button.data( ‘uploader_title’ ),
button: {
text: button.data( ‘uploader_button_text’ ),
…
This allows the labels you’ve defined in the meta box to get passed along to the upload media box.
Thank you very much. This worked for me. It is now functioning exactly like WordPress Featured Image. Thanks!
How can i get the image on the front of the page?
You can get image follow this code :
“img-responsive” ) ); ?>
$avatar_id = get_post_meta( $post_id, “_listing_image_id”, true );
$image = wp_get_attachment_image( $avatar_id, “thumbnail”, “”, array( “class” => “img-responsive” ) );
screenshot code : http://prntscr.com/ccg09u
If above code not working use this one
$avatar_id = get_post_meta( get_the_ID(), ‘_listing_image_id’, true );
$image = wp_get_attachment_image_src( $avatar_id, “thumbnail”, “”, array( “class”=> “img-responsive” ) );
hey! this is great, just what i was looking for. I am seeing the meta box in WP but when I click to set the imagen, the modal window isn’t opening…
any advice?
I just copied and pasted your code, also added and changed some suggestions in the comments, still not working….
thank you!
Hi I’ve problems to display this image, so I wrote additional code (functiosn.php):
ID, $value, true);
if (!empty ($image_id)) {
return is_array ($image_id) ? stripslashes_deep ($image_id) : stripslashes (wp_kses_decode_entities ($image_id));
} else {
return false;
}
}?>
So I can display the image in two Ways (In my theme, I wrote this into a custom page template, directly in the loop…):
Only the URL so I/You can use the URL anywhere:
The image with tags and WP-classes:
So, I hope this helps somebody …. or is there any other possibility to show the image?
Hi I’ve problems to display this image, so I wrote additional code (functiosn.php):
function listing_image_get_meta ($value) {
global $post;
$image_id = get_post_meta ($post->ID, $value, true);
if (!empty ($image_id)) {
return is_array ($image_id) ? stripslashes_deep ($image_id) : stripslashes (wp_kses_decode_entities ($image_id));
} else {
return false;
}
}
So I can display the image in two Ways (In my theme, I wrote this into a custom page template, directly in the loop…):
Only the URL so I/You can use the URL anywhere:
$imagething = wp_get_attachment_image_src( listing_image_get_meta(‘_listing_image_id’), ‘full’); echo $imagething[0]; //instead of ‘full’ you can use any featured/registered image-size
The image with tags and WP-classes:
echo wp_get_attachment_image( listing_image_get_meta(‘_listing_image_id’), ‘full’); //instead of ‘full’ you can use any featured/registered image-size
So, I hope this helps somebody …. or is there any other possibility to show the image?
Amazing code, however i ran into some issues when using this:
I’d literally spent hours trying to get your code to work when i figured out that this website converts the standard coding apostrophe into the quote-looking apostrophe. If anyone else runs into problems with this code, try deleting the apostrophes and retyping them.
I Have Try This code But still Not Working I don, t use Any Plugin . I Have Directly paste Code in Fuction.php and also Paste Script File .. So Please Tell me What I do … Thanks
Maybe I’m missing something, but I cannot get it to work.
I’ve got the meta box displaying, sort of. That works, and I’m enqueue-ing the script properly. However, “Set listing image” link does nothing; it just has the url of javascript.
you sure the JS is loading? I’d start there.
Awesome, just what I needed thanks!
For the people who did have the Listed image box, but not clickable. try have a look if the javascript is loading well.
I added this code above the code in functions.php:
function add_admin_scripts( $hook ) {
global $post;
if ( $hook == ‘post-new.php’ || $hook == ‘post.php’ ) {
if ( ‘post’ === $post->post_type ) {
wp_enqueue_script( ‘myscript’, get_stylesheet_directory_uri().’/js/scripts.js’ );
}
}
}
add_action( ‘admin_enqueue_scripts’, ‘add_admin_scripts’, 10, 1 );
And then it was loaded at the post edit page. (it wasnt loading before)
Hope it helps people
Hi, this post has helped me a lot.
I have managed to create my featured image in a custom post. I can carry it and it is kept wondrous.
But I’m having trouble showing it on my home page. I have tried with the comments codes from above but they do not work for me.
Could you help me?
Thank you very much.
Greetings.
PS: I apologize for my English, is that I use the Google translator.
Hello, is there a way to auto-set the second image as featured image in this box?
Hi there, how do I display the listing image in my theme?
This is exactly what I want to know too. This guide is fine, but it doesn’t specify what we need to display the listing image in the theme templates.
Hi there, how do I display the listing image in my theme?
Hi maasoud,
To display the picture, just look at my old comment 🙂
https://hugh.blog/2015/12/18/create-a-custom-featured-image-box/#comment-9107
Great post!