WP 3-way voting system: On to something! Please help!

Here’s a simple solution. Append the ratings to the end of the post content:

add_filter('the_content', 'add_ratings_to_content', 4);

// remove ratings from excerpts
add_filter('get_the_excerpt', create_function('', 'remove_filter("the_content", "add_ratings_to_content", 6); return;'), 5);

function add_ratings_to_content($content){
  global $post;
  if(is_single()) $content .= the_ratings($post->ID);
  return $content;
}

Displays the current rating:

function get_current_rating($post_id){
  $votes = get_option("votes_{$post_id}");

  // handle your rating format here
  $output="";
  if(isset($_COOKIE["rated_{$post_id}"])) $output .= "Your rating: ".esc_attr($_COOKIE["rated_{$post_id}"]);
  if(is_array($votes)):
    $output .= isset($votes['bad']) ? "{$votes['bad']} people think this sucks." : null;
    $output .= isset($votes['meh']) ? "{$votes['meh']} people said meh." : null;
    $output .= isset($votes['good']) ? "{$votes['good']} people think this post was good." : null;
  else:
    $output = "no votes yet";
  endif;
  return $output;
}

The ajax request. Use $_SERVER['REMOTE_ADDR'] to do a IP check for multiple votes because cookies can be deleted easily (and store the IP+post id somewhere, like a transient)

add_action('init', 'process_vote');
function process_vote() {
  if($_GET['vote']):
    $rating = esc_attr($_GET['vote']);
    $post_id =  esc_attr($_GET['post_id']);

    $already_voted = isset($_COOKIE["rated_{$post_id}"]) ? true : false;
    $current_rating = get_current_rating($post_id);

    if ($post_id && in_array($rating, array('bad', 'meh', 'good')) && !$already_voted):
      // update db
      $votes = get_option("votes_{$post_id}");
      $votes[$rating] = isset($votes[$rating]) ? ($votes[$rating]+1) : 1;
      update_option("votes_{$post_id}", $votes);

      setcookie("rated_{$post_id}", $rating, time() + (86400 * 30)); // 30 day cookie
      echo get_current_rating($post_id);
    else:
      echo "Already voted?";
    endif;

    die();
  endif;
}

the HTML for the ratings, simple stuff, no css:

function the_ratings($post_id = false, $disabled = false){
  $already_voted = isset($_COOKIE["rated_{$post_id}"]) ? true : false;

  ob_start(); ?>
  <?php if(!$already_voted && !$disabled): ?>
  <p>How would you rate this?</p>
  <ul class="vote-process">
    <li><a rel="<?php echo $post_id; ?>">bad</a></li>
    <li><a rel="<?php echo $post_id; ?>">meh</a></li>
    <li><a rel="<?php echo $post_id; ?>">good</a></li>
  </ul>
  <?php endif; ?>

  <div class="vote-status">
    <?php echo get_current_rating($post_id); ?>
  </div>
 <?php
 return ob_get_clean();
}

The JavaScript, included in the page footer.

add_action("wp_footer", "ratings_js");
function ratings_js(){ ?>
  <script type="text/javascript">
    /* <![CDATA[ */

    jQuery(document).ready(function($){
      $(".vote-process a").click(function () {

        var id = $(this).attr('rel');
        var post = $("#post-"+id);
        var link = $(this).html();

        $.ajax({
          type: "GET",
          url: "<?php echo home_url("https://wordpress.stackexchange.com/"); ?>",
          data: {
            post_id: id,
            vote: link
          },

          beforeSend: function() {
            post.find(".vote-status").html("Please wait...");
          },
          success: function(response){
            post.find(".vote-status").html(response);
            post.find(".vote-process").remove();
          }
        });
      });

    });
    /* ]]> */
  </script>
   <?php
}

Remove the votes_postid option when a post is deleted:

add_action('delete_post', 'remove_votes');
function remove_votes($post_id){
  delete_option("votes_{$post_id}");
  return $post_id;
}

I’d still recommend using CDNvote, because the code is very simple and flexible, and uses it’s own database table…