Show custom-field selection – WordPress

I added a content rating system to my platform where the authors can select which audience their post is appropriate for. Currently, these options are available:

  • Unrated
  • G
  • PG
  • R

The code that I use to display the rating options on the post edit page is:

Read More
// Article Content Rating
add_action( 'add_meta_boxes', 'rating_select_box' );
function rating_select_box() {
    add_meta_box(
        'rating_select_box', // id, used as the html id att
        __( 'Content Rating (optional)' ), // meta box title
        'rating_select_cb', // callback function, spits out the content
        'post', // post type or page. This adds to posts only
        'side', // context, where on the screen
        'low' // priority, where should this go in the context
    );

}

function rating_select_cb( $post ) {
    global $wpdb;
    $value = get_post_meta($post->ID, 'rating', true);
    echo '<div class="misc-pub-section misc-pub-section-last"><span id="timestamp"><label>Article Content Rating: </label>';

    $ratings = array(
        1 => ' G ',
        2 => ' PG ',
        3 => ' R ',
    );

    echo '<select name="rating">';
    echo '<option value=""' . ((($value == '') || !isset($ratings[$value])) ? ' selected="selected"' : '') . '> Unrated </option>';

    // output each rating as an option
    foreach ($ratings as $id => $text) {
        echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
    }
    echo '</select>';

    echo '</span></div>';
}

add_action( 'save_post', 'save_metadata');

function save_metadata($postid)
{   
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return false;
    if ( !current_user_can( 'edit_page', $postid ) ) return false;
    if( empty($postid) ) return false;


    if ( is_null($_REQUEST["rating"]) ) {
        delete_post_meta($postid, 'rating');
    } else {
        update_post_meta($postid, 'rating', $_REQUEST['rating']);
    }

}
// END Article Content Rating

Now, the problem is, what code do I add to single.php to display their choice? So for instance, if the author selected PG, then I want to echo 'Content Rating: PG'; or if it was on default (unrated), I want to echo 'Content Rating: Unrated';. How is this possible? Ideally, a solution that is light on the server as my platform is heavily trafficked.

Related posts

Leave a Reply

2 comments

  1. You already use the delete_post_meta() and update_post_meta() functions to remove and modify the custom values. Simply use the get_post_meta() function to obtain the value for the current post, and echo it out as you see fit.

    If you’re in The Loop, it would be something like:

    $rating = get_post_meta(get_the_ID(), 'rating', TRUE);
    

    Edit:

    You already know your ID to rating mapping (I might make this mapping a global array, or some defines, or something similar). Simply use that to look up the string to output:

    $ratings = array(
        1 => 'G',
        2 => 'PG',
        3 => 'R'
    );
    
    if(array_key_exists($rating, $ratings)) {
        echo "Content Rating: $ratings[$rating]";
    } else {
        echo "Content Rating: Unrated";
    }
    
  2. It looks as if you’re saving the key to your custom field rather than its value. I suppose this would be alright if you planned on redeclaring your $ratings array, or (God forbid) use it globally. But still, it would probably be best if you saved the actual Rating rather than its ID number.

    So change this line:

    foreach ($ratings as $id => $text) {
        echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
    }
    

    To this:

    echo '<option value="Unrated"' . ((!$value || $value == 'Unrated' ? ' selected="selected"' : '') . '">Unrated</option>';
    foreach ($ratings as $id => $text) {
        echo '<option value="' .trim($text). '"' . (($value == trim($text)) ? ' selected="selected"' : '') . '">' . $text. '</option>';
    }
    

    After setting your value within the post, you can add this in single.php:

    if(have_posts()) : while(have_posts()) : the_post();
        echo 'Content Rating: '.get_post_meta($post->ID, 'rating', true);
    endwhile;endif;
    

    UPDATE:

    As mentioned in my comments, I personally try to avoid globals and redeclaring things as much as possible. So if you would prefer to still reference your ratings by Key, you can get around globals and redeclaring your ratings array by adding a few simple functions:

    functions.php

    function gw_get_ratings_array()
    {
        $ratings = array(
            1 => 'G',
            2 => 'PG',
            3 => 'R'
        );
        return $ratings;
    }
    function gw_get_rating($key=0)
    {
        $i = (int)$key;
        $ratings = gw_get_ratings_array();
        return isset($ratings[$i]) && $ratings[$i] ? $ratings[$i] : 'Unrated';
    }
    

    single.php

    if(have_posts()) : while(have_posts()) : the_post();
        $rating_id = get_post_meta($post->ID, 'rating', true);
        echo 'Content Rating: '.gw_get_rating($rating_id);
    endwhile;endif;
    

    This way, if you ever need to add more Rating Types, you only need to alter the gw_get_ratings_array function rather than searching for each declaration of the array itself.