I need to add a custom “cover” to every new post — plugin or custom setup?

Another solution, that doesn’t invoke page attributes:

Explanation: To-Do List

Go and download the RW_Meta_Box Library. I’m one of the authors/contributers.

The Plugins

Here you can see two small plugins (which I wrote especially for your question).

Input

The first one is a dependency of the RW Meta Box library. You just change what you need (User cap checks) and upload it to your plugins folder. The change you need to make is pretty simple: Search for the right User Role or Capability and add it where you currently can read 'edit_theme_options'. It should match your designers capability but not your authors.

It adds two textarea meta boxes.

<?php
! defined( 'ABSPATH' ) AND exit;
/** Plugin Name: (#65707) »kaiser« Add Meta Boxes */

function wpse65707_add_meta_boxes()
{
    // Don't add it for all users, but only for your designers
    if (
        ! current_user_can( 'edit_theme_options' ) # CHANGE ME!!!
        OR ! class_exists( 'RW_Meta_Box' )
    )
        return;

    $prefix = 'wpse65707_';
    $meta_boxes[] = array(
        // Meta box id, UNIQUE per meta box
         'id' => 'cover'
        // Meta box title - Will appear at the drag and drop handle bar
        ,'title' => 'Designers Space'
        // Post types, accept custom post types as well - DEFAULT is array('post'); (optional)
        ,'pages' => array( 'post' )
        // Where the meta box appear: normal (default), advanced, side; optional
        ,'context' => 'normal'
        // Order of meta box: high (default), low; optional
        ,'priority' => 'high'
        // List of meta fields
        ,'fields' => array(
            array(
                 'name' => 'Styles'
                ,'desc' => "Only valid CSS here"
                ,'id'   => "{$prefix}styles"
                ,'type' => 'textarea'
                ,'std'  => "h1 { color: #009ee0; }"
                ,'cols' => "40"
                ,'rows' => "8"
            ),
            array(
                 'name' => 'MarkUp'
                ,'desc' => "Only valid HTML here"
                ,'id'   => "{$prefix}markup"
                ,'type' => 'textarea'
                ,'std'  => "<h1>Hello Me!</h1>"
                ,'cols' => "40"
                ,'rows' => "8"
            )
        )
    );

    # Add additional Meta Boxes here.
    # For example a drop-down with a list of users that
    # have a custom role of "Designer"
    # (Hint) Use the "Members" plugin for that and 
    # WP_User_Query to get the users as values

    foreach ( $meta_boxes as $meta_box )
        new RW_Meta_Box( $meta_box );
}
# Performance: Only load on post edit & new admin UI screens.
add_action( 'load-post-new.php', 'wpse65707_add_meta_boxes' );
add_action( 'load-post.php', 'wpse65707_add_meta_boxes' );

Output

This one now cares about our output.

The 1st task it has is adding our styles to the wp_head-hook. This way, we have the possibility to inject whatever custom style the Designer adds.

The 2nd thing it does is adding the current post ID to the post_class filter for the post_class(); template tag. This way, we can easily target only our current post content and nothing aside it.

The 3rd functionality is a parser. This parser allows your designers to add template tags via an abstraction layer: Custom %Template Tags%. So everything that is defined inside the wpse65707_custom_post_styles_parser will be replaced with the set template tag. The function itself is a filter callback for the_content, so you don’t really have to change anything to get it working with whatever theme you’re using.

<?php
! defined( 'ABSPATH' ) AND exit;
/** Plugin Name: (#65707) »kaiser« Custom Post Styles */

// Add custom styles to the `wp_head` hook in the header.php file.
function wpse65707_custom_post_styles()
{
    $styles = get_post_meta( get_the_ID(), 'wpse65707_styles', true );
    $styles = str_replace( 
         '%ID%'
        ,get_the_ID()
        ,$styles
    );

    return print "<style type="text/css>{$styles}</style>";
}
add_action( "wp_head', 'wpse65707_custom_post_styles' );

// Add the plain ID to the post classes for easier styling
// Prevents overriding everything else outside
function wpse65707_post_class ( $classes )
{
    $classes[] = get_the_ID();
    return $classes;
} 
add_filter ( 'post_class' , 'wpse65707_post_class' );

// Parse the content to add Template tags on the fly
function wpse65707_custom_post_styles_parser( $content )
{
    $markup = get_post_meta( get_the_ID(), 'wpse65707_markup', true );
    return strtr(
         $markup
        ,array(
             '%CONTENT%' => $content
            ,'%AUTHOR%'  => get_the_author()
            // Add other template tags here
         )
    );
}
add_filter( 'the_content', 'wpse65707_custom_post_styles_parser' );

Templates: single.php & header.php

The only things that are important to get this working with a theme are the following template tags inside those two files:

  • header.php must have a wp_head() tag.
  • single.php must use the post_class(); function on the post container div/article HTML tag.
  • single.php must use the_content(); to display its content.

How does it work now?

It’s easy: Every template tag, that is allowed inside wpse65707_custom_post_styles_parser(), will be exchanged with what your designer wrote.

// Example content for the "MarkUp"-Meta Box
<h1>Hello Me!</h1>
<h2>A fairy tale by %AUTHOR%</h2>
This is story of love and joy.
%CONTENT%
<p>We hope you liked it.</p>

Now %CONTENT% gets replaced with the actual post content and %AUTHOR%, with the authors display name. Feel free to extend it.

Important is the only tag, that your designers should use to prefix their styles: The %ID% tag. This makes sure, that they aren’t targeting anything outside the current article container.

That’s all folks!