May 19, 2010
How to Make WP Custom Fields Better
Working with custom fields is really great. It gives you an opportunity to integrate complex dynamic content into a site with proper planning and development. Setting up custom fields takes a little though, but when planned well this technique brings great power to all users of the WP site without too much “techy stuff.”
One of the problems with WordPress’ custom fields is that they are pretty bare bones, not user friendly. There are no instructions for a user, and more importantly if any given field is no longer is use by a page or post IT GETS DELETED! C’mon WP, get with it.

It’s my pleasure to present to you Steve Taylor’s fix. You’ll see that with minimal configuration (only thing required to touch is the $customFields array) you can have a much better solution.
Here is a brief explination of its parts. The name key is the custom field slug. The title is what will be displayed in the new custom field within the dashboard. The description I found useful for on screen instructions and reminders of how the field is used. The type determines what is laid out in new field area, presets include textarea, checkbox, and plain ol’ text. The scope determines in which post type (page/post) this field available for. And the capability key is for permissions.
You may not enjoy permanent custom fields.
<?php
if ( !class_exists('myCustomFields') ) {
class myCustomFields {
/**
* @var string $prefix The prefix for storing custom fields in the postmeta table
*/
var $prefix = '';
/**
* @var array $customFields Defines the custom fields available
*/
var $customFields = array(
array(
"name" => "Sidebar_Heading",
"title" => "Sidebar Heading",
"description" => "Filling this out will overwrite the default sidebar heading.",
"type" => "text",
"scope" => array( "post", "page" ),
"capability" => "edit_posts"
),
array(
"name" => "Sidebar_Thumbnail",
"title" => "Sidebar Thumbnail",
"description" => "Filling this out will give this item a sidebar thumbnail. After uploading use the file name. <br />{ex: image.jpg}",
"type" => "text",
"scope" => array( "post" ),
"capability" => "edit_posts"
),
array(
"name" => "Artist_Name",
"title" => "Artists Name {for sidebar}",
"description" => "Filling this out in an artist post will give the artist his own sidebar. <br />Using the same artist name for a store item or free item will put that item in the artist sidebar.<br />{ex: Tone Tank}",
"type" => "text",
"scope" => array( "post" ),
"capability" => "edit_posts"
)
);
/**
* PHP 4 Compatible Constructor
*/
function myCustomFields() { $this->__construct(); }
/**
* PHP 5 Constructor
*/
function __construct() {
add_action( 'admin_menu', array( &$this, 'createCustomFields' ) );
add_action( 'save_post', array( &$this, 'saveCustomFields' ), 1, 2 );
// Comment this line out if you want to keep default custom fields meta box
add_action( 'do_meta_boxes', array( &$this, 'removeDefaultCustomFields' ), 10, 3 );
}
/**
* Remove the default Custom Fields meta box
*/
function removeDefaultCustomFields( $type, $context, $post ) {
foreach ( array( 'normal', 'advanced', 'side' ) as $context ) {
remove_meta_box( 'postcustom', 'post', $context );
remove_meta_box( 'postcustom', 'page', $context );
//Use the line below instead of the line above for WP versions older than 2.9.1
//remove_meta_box( 'pagecustomdiv', 'page', $context );
}
}
/**
* Create the new Custom Fields meta box
*/
function createCustomFields() {
if ( function_exists( 'add_meta_box' ) ) {
add_meta_box( 'my-custom-fields', 'Custom Fields', array( &$this, 'displayCustomFields' ), 'page', 'normal', 'high' );
add_meta_box( 'my-custom-fields', 'Custom Fields', array( &$this, 'displayCustomFields' ), 'post', 'normal', 'high' );
}
}
/**
* Display the new Custom Fields meta box
*/
function displayCustomFields() {
global $post;
?>
<div class="form-wrap">
<?php
wp_nonce_field( 'my-custom-fields', 'my-custom-fields_wpnonce', false, true );
foreach ( $this->customFields as $customField ) {
// Check scope
$scope = $customField[ 'scope' ];
$output = false;
foreach ( $scope as $scopeItem ) {
switch ( $scopeItem ) {
case "post": {
// Output on any post screen
if ( basename( $_SERVER['SCRIPT_FILENAME'] )=="post-new.php" || $post->post_type=="post" )
$output = true;
break;
}
case "page": {
// Output on any page screen
if ( basename( $_SERVER['SCRIPT_FILENAME'] )=="page-new.php" || $post->post_type=="page" )
$output = true;
break;
}
}
if ( $output ) break;
}
// Check capability
if ( !current_user_can( $customField['capability'], $post->ID ) )
$output = false;
// Output if allowed
if ( $output ) { ?>
<div class="form-field form-required">
<?php
switch ( $customField[ 'type' ] ) {
case "checkbox": {
// Checkbox
echo '<label for="' . $this->prefix . $customField[ 'name' ] .'" style="display:inline;"><b>' . $customField[ 'title' ] . '</b></label> ';
echo '<input type="checkbox" name="' . $this->prefix . $customField['name'] . '" id="' . $this->prefix . $customField['name'] . '" value="yes"';
if ( get_post_meta( $post->ID, $this->prefix . $customField['name'], true ) == "yes" )
echo ' checked="checked"';
echo '" style="width: auto;" />';
break;
}
case "textarea": {
// Text area
echo '<label for="' . $this->prefix . $customField[ 'name' ] .'"><b>' . $customField[ 'title' ] . '</b></label>';
echo '<textarea name="' . $this->prefix . $customField[ 'name' ] . '" id="' . $this->prefix . $customField[ 'name' ] . '" columns="30" rows="3">' . htmlspecialchars( get_post_meta( $post->ID, $this->prefix . $customField[ 'name' ], true ) ) . '</textarea>';
break;
}
default: {
// Plain text field
echo '<label for="' . $this->prefix . $customField[ 'name' ] .'"><b>' . $customField[ 'title' ] . '</b></label>';
echo '<input type="text" name="' . $this->prefix . $customField[ 'name' ] . '" id="' . $this->prefix . $customField[ 'name' ] . '" value="' . htmlspecialchars( get_post_meta( $post->ID, $this->prefix . $customField[ 'name' ], true ) ) . '" />';
break;
}
}
?>
<?php if ( $customField[ 'description' ] ) echo '<p>' . $customField[ 'description' ] . '</p>'; ?>
</div>
<?php
}
} ?>
</div>
<?php
}
/**
* Save the new Custom Fields values
*/
function saveCustomFields( $post_id, $post ) {
if ( !wp_verify_nonce( $_POST[ 'my-custom-fields_wpnonce' ], 'my-custom-fields' ) )
return;
if ( !current_user_can( 'edit_post', $post_id ) )
return;
if ( $post->post_type != 'page' && $post->post_type != 'post' )
return;
foreach ( $this->customFields as $customField ) {
if ( current_user_can( $customField['capability'], $post_id ) ) {
if ( isset( $_POST[ $this->prefix . $customField['name'] ] ) && trim( $_POST[ $this->prefix . $customField['name'] ] ) ) {
update_post_meta( $post_id, $this->prefix . $customField[ 'name' ], $_POST[ $this->prefix . $customField['name'] ] );
} else {
delete_post_meta( $post_id, $this->prefix . $customField[ 'name' ] );
}
}
}
}
} // End Class
} // End if class exists statement
// Instantiate the class
if ( class_exists('myCustomFields') ) {
$myCustomFields_var = new myCustomFields();
}
add_filter('tiny_mce_before_init', 'add_noborder');
function add_noborder($initArray) {
$initArray['theme_advanced_styles'] = "noborder=noborder";
return $initArray;
}
