Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Inlcuding custom fields and uploads in a WordPress post
function create_post_your_post() {
register_post_type( 'your_post',
'labels' => array(
'name' => __( 'Your Post' ),
'public' => true,
'hierarchical' => true,
'has_archive' => true,
'supports' => array(
'taxonomies' => array(
register_taxonomy_for_object_type( 'category', 'your_post' );
register_taxonomy_for_object_type( 'post_tag', 'your_post' );
add_action( 'init', 'create_post_your_post' );
function add_your_fields_meta_box() {
'your_fields_meta_box', // $id
'Your Fields', // $title
'show_your_fields_meta_box', // $callback
'your_post', // $screen
'normal', // $context
'high' // $priority
add_action( 'add_meta_boxes', 'add_your_fields_meta_box' );
function show_your_fields_meta_box() {
global $post;
$meta = get_post_meta( $post->ID, 'your_fields', true ); ?>
<input type="hidden" name="your_meta_box_nonce" value="<?php echo wp_create_nonce( basename(__FILE__) ); ?>">
<label for="your_fields[text]">Input Text</label>
<input type="text" name="your_fields[text]" id="your_fields[text]" class="regular-text" value="<?php if (is_array($meta) && isset($meta['text'])) { echo $meta['text']; } ?>">
<label for="your_fields[textarea]">Textarea</label>
<textarea name="your_fields[textarea]" id="your_fields[textarea]" rows="5" cols="30" style="width:500px;"><?php echo $meta['textarea']; ?></textarea>
<label for="your_fields[checkbox]">Checkbox
<input type="checkbox" name="your_fields[checkbox]" value="checkbox" <?php if ( $meta['checkbox'] === 'checkbox' ) echo 'checked'; ?>>
<label for="your_fields[select]">Select Menu</label>
<select name="your_fields[select]" id="your_fields[select]">
<option value="option-one" <?php selected( $meta['select'], 'option-one' ); ?>>Option One</option>
<option value="option-two" <?php selected( $meta['select'], 'option-two' ); ?>>Option Two</option>
<label for="your_fields[image]">Image Upload</label><br>
<input type="text" name="your_fields[image]" id="your_fields[image]" class="meta-image regular-text" value="<?php echo $meta['image']; ?>">
<input type="button" class="button image-upload" value="Browse">
<div class="image-preview"><img src="<?php echo $meta['image']; ?>" style="max-width: 250px;"></div>
jQuery(document).ready(function ($) {
// Instantiates the variable that holds the media library frame.
var meta_image_frame;
// Runs when the image button is clicked.
$('.image-upload').click(function (e) {
// Get preview pane
var meta_image_preview = $(this).parent().parent().children('.image-preview');
// Prevents the default action from occuring.
var meta_image = $(this).parent().children('.meta-image');
// If the frame already exists, re-open it.
if (meta_image_frame) {;
// Sets up the media library frame
meta_image_frame = ={
title: meta_image.title,
button: {
text: meta_image.button
// Runs when an image is selected.
meta_image_frame.on('select', function () {
// Grabs the attachment selection and creates a JSON representation of the model.
var media_attachment = meta_image_frame.state().get('selection').first().toJSON();
// Sends the attachment URL to our custom image input field.
meta_image_preview.children('img').attr('src', media_attachment.url);
// Opens the media library frame.;
<?php }
function save_your_fields_meta( $post_id ) {
// verify nonce
if ( isset($_POST['your_meta_box_nonce'])
&& !wp_verify_nonce( $_POST['your_meta_box_nonce'], basename(__FILE__) ) ) {
return $post_id;
// check autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
// check permissions
if (isset($_POST['post_type'])) { //Fix 2
if ( 'page' === $_POST['post_type'] ) {
if ( !current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
} elseif ( !current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
$old = get_post_meta( $post_id, 'your_fields', true );
if (isset($_POST['your_fields'])) { //Fix 3
$new = $_POST['your_fields'];
if ( $new && $new !== $old ) {
update_post_meta( $post_id, 'your_fields', $new );
} elseif ( '' === $new && $old ) {
delete_post_meta( $post_id, 'your_fields', $old );
add_action( 'save_post', 'save_your_fields_meta' );
Copy link

leonardoapolinario commented Nov 10, 2017

In Linux, you must wrap $meta['something'] with:
"if (is_array($meta) && isset($meta['something'])){"
to not show warnings.

Copy link

jeffiec commented Dec 17, 2017

Im having issue with the image no displaying in the preview after selecting, any quick thoughts?
i haven't changed the script at all, except added my prefixes to the html, but everything matches even console logged:
meta_image_preview.children('img').attr('src', media_attachment.url);
and the proper url shows up, just doesnt show up in preview pan.
any help appreciated.

Copy link

AhmedHelalAhmed commented Mar 30, 2018

An other solution for warnings.
put first line in the file :
error_reporting(E_ERROR | E_PARSE);

Copy link

MarkIvanowich commented Aug 17, 2018

If later you wish to sort your posts by any of these fields, it will not work.

The website article and these pages are describing how to store numerous fields into one meta_key. While this is efficient for fast loading when displaying, you can never use WP_Query to sort posts by an individual field using this method. I suggest using Wordpress' Developer Handbook on Custom Meta Boxes to save an individual field as a query-able meta_key. You could even create a hybrid of the two websites to get the best of both methods while keeping one Meta Box.

Hopefully this saves someone some headache that I just experienced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment