[MU] Sistema de Votação com Estrelas

Sistema de Votação com Estrelas (exibição automática)

Objetivo: Fornecer um MU-Plugin completo que substitui wp-postratings e similares, com exibição automática das estrelas no final de cada post, sem necessidade de inserir shortcode manualmente. O sistema registra votos por IP, evita múltiplos votos e atualiza a média e total de votos.

Código do MU-Plugin: neodoor-ratings.php

Crie o arquivo dentro de wp-content/mu-plugins/neodoor-ratings/neodoor-ratings.php (ou direto na pasta mu-plugins se preferir).

<?php
/**
 * Plugin Name:  Neodoor Ratings (Unificado)
 * Description:  Sistema de votação com estrelas (1 a 5), exibido automaticamente ao final de cada post. Substitui wp-postratings.
 * Version:      2.0
 * Author:       Reinaldo (Neodoor.neo)
 */

if ( ! defined( 'ABSPATH' ) ) exit;

class Neodoor_Ratings_Unified {
    private static $instance = null;

    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action( 'init', [ $this, 'handle_vote' ] );
        add_filter( 'the_content', [ $this, 'append_ratings_to_content' ], 20 );
        add_action( 'wp_head', [ $this, 'inline_css' ] );
    }

    /**
     * Adiciona o sistema de votação automaticamente após o conteúdo de cada post.
     */
    public function append_ratings_to_content( $content ) {
        if ( is_singular( 'post' ) && in_the_loop() && is_main_query() ) {
            $content .= $this->render_ratings();
        }
        return $content;
    }

    /**
     * Renderiza o HTML das estrelas e informações de voto.
     */
    private function render_ratings() {
        $post_id = get_the_ID();
        $avg = get_post_meta( $post_id, '_rating_average', true ) ?: 0;
        $count = get_post_meta( $post_id, '_rating_count', true ) ?: 0;

        // Mensagem de feedback (vindo da URL após voto)
        $msg = '';
        if ( isset( $_GET['vote_status'] ) && $_GET['vote_status'] == 'success' && isset( $_GET['rated_post'] ) && $_GET['rated_post'] == $post_id ) {
            $msg = '<p style="color:green; margin:0 0 10px 0;">✅ Voto computado! Obrigado.</p>';
        } elseif ( isset( $_GET['vote_status'] ) && $_GET['vote_status'] == 'already_voted' && isset( $_GET['rated_post'] ) && $_GET['rated_post'] == $post_id ) {
            $msg = '<p style="color:orange; margin:0 0 10px 0;">⚠️ Você já votou neste conteúdo.</p>';
        }

        // Gera links para votar (1 a 5 estrelas)
        $vote_links = '';
        for ( $i = 1; $i <= 5; $i++ ) {
            $url = add_query_arg( [ 'rate_post' => $post_id, 'rating' => $i ], get_permalink() );
            $star_class = ( $i <= round( $avg ) ) ? 'star-filled' : 'star-empty';
            $vote_links .= '<a href="' . esc_url( $url ) . '" class="neodoor-star ' . $star_class . '" data-rating="' . $i . '">★</a>';
        }

        return '
        <div class="neodoor-ratings-wrapper">
            ' . $msg . '
            <div class="neodoor-stars-container">' . $vote_links . '</div>
            <div class="neodoor-rating-stats">Média: ' . number_format( $avg, 1 ) . ' (' . $count . ' voto' . ( $count != 1 ? 's' : '' ) . ')</div>
        </div>';
    }

    /**
     * Processa o voto quando os parâmetros rate_post e rating são enviados via GET.
     */
    public function handle_vote() {
        if ( ! isset( $_GET['rate_post'], $_GET['rating'] ) ) return;

        $post_id = intval( $_GET['rate_post'] );
        $rating  = intval( $_GET['rating'] );
        if ( $rating < 1 || $rating > 5 ) return;

        // Verifica voto por IP (evita múltiplos votos)
        $ip = $_SERVER['REMOTE_ADDR'];
        $voted_ips = get_post_meta( $post_id, '_rating_voted_ips', true );
        if ( ! is_array( $voted_ips ) ) $voted_ips = [];
        if ( in_array( $ip, $voted_ips ) ) {
            $redirect_url = add_query_arg( [ 'vote_status' => 'already_voted', 'rated_post' => $post_id ], get_permalink( $post_id ) );
            wp_redirect( $redirect_url );
            exit;
        }

        // Atualiza métricas
        $total = get_post_meta( $post_id, '_rating_total', true ) ?: 0;
        $count = get_post_meta( $post_id, '_rating_count', true ) ?: 0;
        $total += $rating;
        $count++;
        $new_avg = $total / $count;

        update_post_meta( $post_id, '_rating_average', $new_avg );
        update_post_meta( $post_id, '_rating_count', $count );
        update_post_meta( $post_id, '_rating_total', $total );

        // Registra IP
        $voted_ips[] = $ip;
        update_post_meta( $post_id, '_rating_voted_ips', $voted_ips );

        // Redireciona com sucesso
        $redirect_url = add_query_arg( [ 'vote_status' => 'success', 'rated_post' => $post_id ], get_permalink( $post_id ) );
        wp_redirect( $redirect_url );
        exit;
    }

    /**
     * Estilos CSS básicos para as estrelas e layout.
     */
    public function inline_css() {
        if ( ! is_singular( 'post' ) ) return;
        echo '<style>
            .neodoor-ratings-wrapper {
                margin: 30px 0 20px;
                padding: 15px 0;
                border-top: 1px solid #eee;
                text-align: center;
            }
            .neodoor-stars-container {
                display: inline-block;
                font-size: 32px;
                letter-spacing: 5px;
            }
            .neodoor-star {
                text-decoration: none;
                color: #ccc;
                transition: color 0.2s;
            }
            .neodoor-star.star-filled {
                color: #ffc107;
            }
            .neodoor-star:hover {
                color: #ffb300;
            }
            .neodoor-rating-stats {
                font-size: 14px;
                color: #666;
                margin-top: 8px;
            }
        </style>';
    }
}

Neodoor_Ratings_Unified::get_instance();

Instalação e uso

  1. Crie o arquivo conforme o caminho indicado.
  2. Não é necessário inserir shortcode – o sistema aparecerá automaticamente ao final de cada post.
  3. Para desativar em posts específicos, você pode usar uma condicional (ex: excluir categorias).
  4. Os votos são registrados por IP. O cookie não é necessário, pois o redirecionamento mantém o estado.

Personalizações comuns

  • Alterar posição das estrelas: no método append_ratings_to_content, troque $content .= ... por $content = ... . $content (para aparecer antes do conteúdo).
  • Restringir a apenas algumas categorias: adicione uma condição como if ( in_category( 'noticias' ) ) dentro do filtro.
  • Mudar cores ou tamanhos: edite o CSS no método inline_css.

Registro no caderno

Data:

Funcionalidade: Votação com estrelas (1 a 5) exibida automaticamente em todos os posts.

Plugins substituídos: wp-postratings e similares.

Testado: ✅ Votos registrados, média atualizada, prevenção de múltiplos votos por IP, exibição automática.

Média: 3.0 (45 votos)