{"id":334,"date":"2026-05-14T11:19:48","date_gmt":"2026-05-14T14:19:48","guid":{"rendered":"https:\/\/neodoor.neo\/?p=334"},"modified":"2026-05-21T09:33:25","modified_gmt":"2026-05-21T12:33:25","slug":"votacao-posts-pages","status":"publish","type":"post","link":"https:\/\/www.portanova.com.br\/notebook\/votacao-posts-pages\/","title":{"rendered":"[MU] Sistema de Vota\u00e7\u00e3o com Estrelas"},"content":{"rendered":"<h2>Sistema de Vota\u00e7\u00e3o com Estrelas (exibi\u00e7\u00e3o autom\u00e1tica)<\/h2>\n<p><strong>Objetivo:<\/strong> Fornecer um MU-Plugin completo que substitui <code>wp-postratings<\/code> e similares, com exibi\u00e7\u00e3o autom\u00e1tica das estrelas no final de cada post, sem necessidade de inserir shortcode manualmente. O sistema registra votos por IP, evita m\u00faltiplos votos e atualiza a m\u00e9dia e total de votos.<\/p>\n<h3>C\u00f3digo do MU-Plugin: <code>neodoor-ratings.php<\/code><\/h3>\n<p>Crie o arquivo dentro de <code>wp-content\/mu-plugins\/neodoor-ratings\/neodoor-ratings.php<\/code> (ou direto na pasta <code>mu-plugins<\/code> se preferir).<\/p>\n<pre><code>&lt;?php\r\n\/**\r\n * Plugin Name:  Neodoor Ratings (Unificado)\r\n * Description:  Sistema de vota\u00e7\u00e3o com estrelas (1 a 5), exibido automaticamente ao final de cada post. Substitui wp-postratings.\r\n * Version:      2.0\r\n * Author:       Reinaldo (Neodoor.neo)\r\n *\/\r\n\r\nif ( ! defined( 'ABSPATH' ) ) exit;\r\n\r\nclass Neodoor_Ratings_Unified {\r\n    private static $instance = null;\r\n\r\n    public static function get_instance() {\r\n        if ( null === self::$instance ) {\r\n            self::$instance = new self();\r\n        }\r\n        return self::$instance;\r\n    }\r\n\r\n    private function __construct() {\r\n        add_action( 'init', [ $this, 'handle_vote' ] );\r\n        add_filter( 'the_content', [ $this, 'append_ratings_to_content' ], 20 );\r\n        add_action( 'wp_head', [ $this, 'inline_css' ] );\r\n    }\r\n\r\n    \/**\r\n     * Adiciona o sistema de vota\u00e7\u00e3o automaticamente ap\u00f3s o conte\u00fado de cada post.\r\n     *\/\r\n    public function append_ratings_to_content( $content ) {\r\n        if ( is_singular( 'post' ) &amp;&amp; in_the_loop() &amp;&amp; is_main_query() ) {\r\n            $content .= $this-&gt;render_ratings();\r\n        }\r\n        return $content;\r\n    }\r\n\r\n    \/**\r\n     * Renderiza o HTML das estrelas e informa\u00e7\u00f5es de voto.\r\n     *\/\r\n    private function render_ratings() {\r\n        $post_id = get_the_ID();\r\n        $avg = get_post_meta( $post_id, '_rating_average', true ) ?: 0;\r\n        $count = get_post_meta( $post_id, '_rating_count', true ) ?: 0;\r\n\r\n        \/\/ Mensagem de feedback (vindo da URL ap\u00f3s voto)\r\n        $msg = '';\r\n        if ( isset( $_GET['vote_status'] ) &amp;&amp; $_GET['vote_status'] == 'success' &amp;&amp; isset( $_GET['rated_post'] ) &amp;&amp; $_GET['rated_post'] == $post_id ) {\r\n            $msg = '&lt;p style=\"color:green; margin:0 0 10px 0;\"&gt;\u2705 Voto computado! Obrigado.&lt;\/p&gt;';\r\n        } elseif ( isset( $_GET['vote_status'] ) &amp;&amp; $_GET['vote_status'] == 'already_voted' &amp;&amp; isset( $_GET['rated_post'] ) &amp;&amp; $_GET['rated_post'] == $post_id ) {\r\n            $msg = '&lt;p style=\"color:orange; margin:0 0 10px 0;\"&gt;\u26a0\ufe0f Voc\u00ea j\u00e1 votou neste conte\u00fado.&lt;\/p&gt;';\r\n        }\r\n\r\n        \/\/ Gera links para votar (1 a 5 estrelas)\r\n        $vote_links = '';\r\n        for ( $i = 1; $i &lt;= 5; $i++ ) {\r\n            $url = add_query_arg( [ 'rate_post' =&gt; $post_id, 'rating' =&gt; $i ], get_permalink() );\r\n            $star_class = ( $i &lt;= round( $avg ) ) ? 'star-filled' : 'star-empty';\r\n            $vote_links .= '&lt;a href=\"' . esc_url( $url ) . '\" class=\"neodoor-star ' . $star_class . '\" data-rating=\"' . $i . '\"&gt;\u2605&lt;\/a&gt;';\r\n        }\r\n\r\n        return '\r\n        &lt;div class=\"neodoor-ratings-wrapper\"&gt;\r\n            ' . $msg . '\r\n            &lt;div class=\"neodoor-stars-container\"&gt;' . $vote_links . '&lt;\/div&gt;\r\n            &lt;div class=\"neodoor-rating-stats\"&gt;M\u00e9dia: ' . number_format( $avg, 1 ) . ' (' . $count . ' voto' . ( $count != 1 ? 's' : '' ) . ')&lt;\/div&gt;\r\n        &lt;\/div&gt;';\r\n    }\r\n\r\n    \/**\r\n     * Processa o voto quando os par\u00e2metros rate_post e rating s\u00e3o enviados via GET.\r\n     *\/\r\n    public function handle_vote() {\r\n        if ( ! isset( $_GET['rate_post'], $_GET['rating'] ) ) return;\r\n\r\n        $post_id = intval( $_GET['rate_post'] );\r\n        $rating  = intval( $_GET['rating'] );\r\n        if ( $rating &lt; 1 || $rating &gt; 5 ) return;\r\n\r\n        \/\/ Verifica voto por IP (evita m\u00faltiplos votos)\r\n        $ip = $_SERVER['REMOTE_ADDR'];\r\n        $voted_ips = get_post_meta( $post_id, '_rating_voted_ips', true );\r\n        if ( ! is_array( $voted_ips ) ) $voted_ips = [];\r\n        if ( in_array( $ip, $voted_ips ) ) {\r\n            $redirect_url = add_query_arg( [ 'vote_status' =&gt; 'already_voted', 'rated_post' =&gt; $post_id ], get_permalink( $post_id ) );\r\n            wp_redirect( $redirect_url );\r\n            exit;\r\n        }\r\n\r\n        \/\/ Atualiza m\u00e9tricas\r\n        $total = get_post_meta( $post_id, '_rating_total', true ) ?: 0;\r\n        $count = get_post_meta( $post_id, '_rating_count', true ) ?: 0;\r\n        $total += $rating;\r\n        $count++;\r\n        $new_avg = $total \/ $count;\r\n\r\n        update_post_meta( $post_id, '_rating_average', $new_avg );\r\n        update_post_meta( $post_id, '_rating_count', $count );\r\n        update_post_meta( $post_id, '_rating_total', $total );\r\n\r\n        \/\/ Registra IP\r\n        $voted_ips[] = $ip;\r\n        update_post_meta( $post_id, '_rating_voted_ips', $voted_ips );\r\n\r\n        \/\/ Redireciona com sucesso\r\n        $redirect_url = add_query_arg( [ 'vote_status' =&gt; 'success', 'rated_post' =&gt; $post_id ], get_permalink( $post_id ) );\r\n        wp_redirect( $redirect_url );\r\n        exit;\r\n    }\r\n\r\n    \/**\r\n     * Estilos CSS b\u00e1sicos para as estrelas e layout.\r\n     *\/\r\n    public function inline_css() {\r\n        if ( ! is_singular( 'post' ) ) return;\r\n        echo '&lt;style&gt;\r\n            .neodoor-ratings-wrapper {\r\n                margin: 30px 0 20px;\r\n                padding: 15px 0;\r\n                border-top: 1px solid #eee;\r\n                text-align: center;\r\n            }\r\n            .neodoor-stars-container {\r\n                display: inline-block;\r\n                font-size: 32px;\r\n                letter-spacing: 5px;\r\n            }\r\n            .neodoor-star {\r\n                text-decoration: none;\r\n                color: #ccc;\r\n                transition: color 0.2s;\r\n            }\r\n            .neodoor-star.star-filled {\r\n                color: #ffc107;\r\n            }\r\n            .neodoor-star:hover {\r\n                color: #ffb300;\r\n            }\r\n            .neodoor-rating-stats {\r\n                font-size: 14px;\r\n                color: #666;\r\n                margin-top: 8px;\r\n            }\r\n        &lt;\/style&gt;';\r\n    }\r\n}\r\n\r\nNeodoor_Ratings_Unified::get_instance();\r\n<\/code><\/pre>\n<h3>Instala\u00e7\u00e3o e uso<\/h3>\n<ol>\n<li>Crie o arquivo conforme o caminho indicado.<\/li>\n<li>N\u00e3o \u00e9 necess\u00e1rio inserir shortcode \u2013 o sistema aparecer\u00e1 automaticamente ao final de cada post.<\/li>\n<li>Para desativar em posts espec\u00edficos, voc\u00ea pode usar uma condicional (ex: excluir categorias).<\/li>\n<li>Os votos s\u00e3o registrados por IP. O cookie n\u00e3o \u00e9 necess\u00e1rio, pois o redirecionamento mant\u00e9m o estado.<\/li>\n<\/ol>\n<h3>Personaliza\u00e7\u00f5es comuns<\/h3>\n<ul>\n<li><strong>Alterar posi\u00e7\u00e3o das estrelas:<\/strong> no m\u00e9todo <code>append_ratings_to_content<\/code>, troque <code>$content .= ...<\/code> por <code>$content = ... . $content<\/code> (para aparecer antes do conte\u00fado).<\/li>\n<li><strong>Restringir a apenas algumas categorias:<\/strong> adicione uma condi\u00e7\u00e3o como <code>if ( in_category( 'noticias' ) )<\/code> dentro do filtro.<\/li>\n<li><strong>Mudar cores ou tamanhos:<\/strong> edite o CSS no m\u00e9todo <code>inline_css<\/code>.<\/li>\n<\/ul>\n<h3>Registro no caderno<\/h3>\n<p><strong>Data:<\/strong> <!--?php echo date('d\/m\/Y'); ?--><\/p>\n<p><strong>Funcionalidade:<\/strong> Vota\u00e7\u00e3o com estrelas (1 a 5) exibida automaticamente em todos os posts.<\/p>\n<p><strong>Plugins substitu\u00eddos:<\/strong> wp-postratings e similares.<\/p>\n<p><strong>Testado:<\/strong> \u2705 Votos registrados, m\u00e9dia atualizada, preven\u00e7\u00e3o de m\u00faltiplos votos por IP, exibi\u00e7\u00e3o autom\u00e1tica.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sistema de Vota\u00e7\u00e3o com Estrelas (exibi\u00e7\u00e3o autom\u00e1tica) Objetivo: Fornecer um MU-Plugin completo que substitui wp-postratings e similares, com exibi\u00e7\u00e3o autom\u00e1tica das estrelas no final de cada post, sem necessidade de inserir shortcode manualmente. O sistema registra votos por IP, evita m\u00faltiplos votos e atualiza a m\u00e9dia e total de votos. C\u00f3digo do MU-Plugin: neodoor-ratings.php Crie [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,4],"tags":[],"class_list":["post-334","post","type-post","status-publish","format-standard","hentry","category-lessons","category-pluginsmu"],"_links":{"self":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts\/334","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/comments?post=334"}],"version-history":[{"count":0,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/posts\/334\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/media?parent=334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/categories?post=334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.portanova.com.br\/notebook\/wp-json\/wp\/v2\/tags?post=334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}