I would keep the primary content field and add a metabox + a secondary instance of the wp editor (using the handy wp_editor
function).
Custom field values are stored in the database as LONGTEXT
, so they can handle just about anything you wish to throw at them.
A class to wrap everything up. There’s a few constants here we’ll use later.
<?php
class Secondary_Content
{
// meta key we'll use to save things.
const META = '_secondary_content';
// nonce name to check
const NONCE = '_s_content_nonce';
// post type to which we'll add the box
const TYPE = 'page';
private static $ins = null;
public static function init()
{
add_action('plugins_loaded', array(self::instance(), '_setup'));
}
public static function instance()
{
is_null(self::$ins) && self::$ins = new self;
return self::$ins;
}
public function _setup()
{
// we'll add actions here later.
}
}
To add the meta box, hook into add_meta_boxes_{{YOUR_POST_TYPE}}
. I’m just going to use pages for this example. Change the value of the TYPE
constant in the class to make it work for a custom post type.
<?php
class Secondary_Content
{
// snip snip
public function _setup()
{
add_action('add_meta_boxes_' . self::TYPE, array($this, 'add_box'));
}
/**
* Adds a meta box to the `page` post type.
*
* @uses add_meta_box
* @return void
*/
public function add_box()
{
add_meta_box(
'secondary-content',
__('Secondary Content', 'wspe'),
array($this, 'box_cb'),
self::TYPE,
'normal',
'high'
);
}
/**
* Metabox callback function.
*
* @access public
* @param object $post The current $post
* @uses get_post_meta
* @uses wp_editor
* @return void
*/
public function box_cb($post)
{
wp_nonce_field(self::NONCE . $post->ID, self::NONCE, false);
wp_editor(
get_post_meta($post->ID, self::META, true),
self::META
);
}
}
The meta box callback is also included above. It just spits out a nonce for us to validate as well as the editor field using wp_editor
.
Now we just need to hook into save_post
and save things. We’ll check to make sure we’re on the right post type. Then validate the nonce and check if the current user has permission to edit the post, then it’s just a matter of calling update_post_meta
or delete_post_meta
as appropriate. The only other thing of note here is that I check to see if the current user can post unfiltered HTML. If they can, I’ll just let whatever go through in the meta box. If not, better run it through wp_filter_post_kses
.
<?php
class Secondary_Content
{
// snip snip
public function _setup()
{
add_action('add_meta_boxes_' . self::TYPE, array($this, 'add_box'));
add_action('save_post', array($this, 'save'), 10, 2);
}
// snip snip
/**
* Hooked into `save_post`. Makes sure this is the request we want and the
* user has permission, then saves the custom field.
*
* @access public
* @param int $post_id
* @param object $post
* @uses wp_verify_nonce
* @uses current_user_can
* @uses update_post_meta
* @uses delete_post_meta
* @return void
*/
public function save($post_id, $post)
{
if(
self::TYPE != $post->post_type ||
(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
) return;
if(
!isset($_POST[self::NONCE]) ||
!wp_verify_nonce($_POST[self::NONCE], self::NONCE . $post_id)
) return;
if(!current_user_can('edit_post', $post_id))
return;
if(!empty($_POST[self::META]))
{
update_post_meta(
$post_id,
self::META,
current_user_can('unfiltered_html') ?
$_POST[self::META] : wp_filter_post_kses($_POST[self::META])
);
}
else
{
delete_post_meta($post_id, self::META);
}
}
}
To fetch this on the front end, you just need to do echo get_post_meta($post->ID, '_secondary_content', true);
somewhere in the loop. But it might be nicer to include a wrapper function in our class.
<?php
class Secondary_Content
{
// snip snip
/**
* Meant to be used as a template tag. A simple helper to spit out our
* secondary content.
*
* @access public
* @param object $post
* @param bool $echo (optional) defaults to true.
* @uses get_post_meta
* @return string
*/
public static function content($post, $echo=true)
{
$res = apply_filters('secondary_content',
get_post_meta($post->ID, self::META, true));
if($echo)
echo $res;
return $res;
}
}
Now you can just do Secondary_Content::content($post);
to fetch things.
A final note: this content won’t get anything nice like wpautop
or the like. If you want to do that, you’ll need to add that as a filter to the final output.
<?php
add_filter('secondary_content', 'wpautop');
The end result:
All of the above as a plugin.