Sistema de votación con estrellas con jQuery, Ajax y PHP

En este tutorial aprenderemos como desarrollar un sistema de votación con jQuery, Ajax y PHP. Con este simple script podrás implementar fácilmente un sistema de votación basado en 5 estrellas dinámico en tus propios proyectos.

Vamos a crear un sistema de votación jQuery con PHP y MySQL. Hemos desarrollado el fichero rating.js para que maneje todas las operaciones con jQuery. Utilizamos Ajax para enviar los puntos de votación al archivo PHP (rating.php). El archivo rating.php se encarga de insertar, o modificar, los datos de la votación a la base de datos MySQL.

Para implementar el sistema de votación con estrellas utilizaremos estos cinco ficheros:

  • rating.js
  • rating.css
  • dbConfig.php
  • index.php
  • rating.php

Creación de la base de datos

La tabla post_rating la utilizaremos para almacenar los datos de la votación. Puedes ver el script para crear dicha tabla, a continuación.

CREATE TABLE `post_rating` (
 `rating_id` int(11) NOT NULL AUTO_INCREMENT,
 `post_id` int(11) NOT NULL,
 `rating_number` int(11) NOT NULL,
 `total_points` int(11) NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 = Block, 0 = Unblock',
 PRIMARY KEY (`rating_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

rating.js

El archivo rating.js contiene todos los código jQuery requeridos para implementar el sistema de votación que deseamos.

/*
 * Star Rating
 * by CodexWorld
 *
 * More info:
 * http://www.codexworld.com
 *
 * Copyright 2015 CodexWorld
 * Released under the MIT license
 * 
 */
 
(function(a){
    a.fn.codexworld_rating_widget = function(p){
        var p = p||{};
        var b = p&&p.starLength?p.starLength:"5";
        var c = p&&p.callbackFunctionName?p.callbackFunctionName:"";
        var e = p&&p.initialValue?p.initialValue:"0";
        var d = p&&p.imageDirectory?p.imageDirectory:"images";
        var r = p&&p.inputAttr?p.inputAttr:"";
        var f = e;
        var g = a(this);
        b = parseInt(b);
        init();
        g.next("ul").children("li").hover(function(){
            $(this).parent().children("li").css('background-position','0px 0px');
            var a = $(this).parent().children("li").index($(this));
            $(this).parent().children("li").slice(0,a+1).css('background-position','0px -28px')
        },function(){});
        g.next("ul").children("li").click(function(){
            var a = $(this).parent().children("li").index($(this));
            var attrVal = (r != '')?g.attr(r):'';
            f = a+1;
            g.val(f);
            if(c != ""){
                eval(c+"("+g.val()+", "+attrVal+")")
            }
        });
        g.next("ul").hover(function(){},function(){
            if(f == ""){
                $(this).children("li").slice(0,f).css('background-position','0px 0px')
            }else{
                $(this).children("li").css('background-position','0px 0px');
                $(this).children("li").slice(0,f).css('background-position','0px -28px')
            }
        });
        function init(){
            $('<div style="clear:both;"></div>').insertAfter(g);
            g.css("float","left");
            var a = $("<ul>");
            a.addClass("codexworld_rating_widget");
            for(var i=1;i<=b;i++){
                a.append('<li style="background-image:url('+d+'/widget_star.gif)"><span>'+i+'</span></li>')
            }
            a.insertAfter(g);
            if(e != ""){
                f = e;
                g.val(e);
                g.next("ul").children("li").slice(0,f).css('background-position','0px -28px')
            }
        }
    }
})(jQuery);

rating.css

Es el encargado de darle estilo a las estrellas y al sistema de votación en sí.

.codexworld_rating_widget{
    padding: 0px;
    margin: 0px;
    float: left;
}
.codexworld_rating_widget li{
    line-height: 0px;
    width: 28px;
    height: 28px;
    padding: 0px;
    margin: 0px;
    margin-left: 2px;
    list-style: none;
    float: left;
    cursor: pointer;
}
.codexworld_rating_widget li span{
    display: none;
}

dbConfig.php

Fichero que establecerá la conexión con la base de datos. Cambia las credenciales por las tuyas propias.

//Database configuration
$dbHost = 'localhost';
$dbUsername = 'root';
$dbPassword = '';
$dbName = 'prueba';

//Connect with the database
$db = new mysqli($dbHost, $dbUsername, $dbPassword, $dbName);
if($db->connect_errno):
    die('Connect error:'.$db->connect_error);
endif;

index.php

Aquí debes incluir la librería jQuery, el fichero rating.js y también, rating.css.

<link href="rating.css" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript" src="rating.js"></script>

Adjunta codexworld_rating_widget cuenta el documento se haya cargado. El método codexworld_rating_widget existe dentro de rating.js. Puedes pasarle al método ciertas opciones con el formato objeto clave/valor.

$(function() {
    $("#rating_star").codexworld_rating_widget({
        starLength: '5',
        initialValue: '',
        callbackFunctionName: 'processRating',
        imageDirectory: 'images/',
        inputAttr: 'postID'
    });
});

Opciones disponibles:

  • strLength: Estrellas que se van a mostrar. Por defecto 5.
  • initialValue: Valor de votación cuando el documento se carga por primera vez. Por defecto 0.
  • callbackFunctionName: Función a la cual se llamará cuando se clique alguna estrella.
  • imageDirectory: Nombre del directorio de la imagen de la estrella. Por defecto 'images'.
  • inputAttr: Valor que se le pasa a la función de devolución, si es que la hay.

Define como función de devolución processRating(). El método codexworld_rating_widget() devuelve ID del post votado y los puntos de votación a la función processRating(). Utilizando Ajax enviaremos el ID y los puntos de votación al archivo rating.php.

function processRating(val, attrVal){
    $.ajax({
        type: 'POST',
        url: 'rating.php',
        data: 'postID='+attrVal+'&ratingPoints='+val,
        dataType: 'json',
        success : function(data) {
            if (data.status == 'ok') {
                alert('You have rated '+val+' to CodexWorld');
                $('#avgrat').text(data.average_rating);
                $('#totalrat').text(data.rating_number);
            }else{
                alert('Some problem occured, please try again.');
            }
        }
    });
}

Cuando la página cargue por primera vez, extraeremos los datos de votación de la base de datos y los mostraremos.

include_once 'dbConfig.php';
//Fetch rating deatails from database
$query = "SELECT rating_number, FORMAT((total_points / rating_number),1) as average_rating FROM post_rating WHERE post_id = 1 AND status = 1";
$result = $db->query($query);
$ratingRow = $result->fetch_assoc();

Dentro del HTML solo necesitamos un campo input con atributos personalizados para definir el ID del post.

<input name="rating" value="0" id="rating_star" type="hidden" postID="1" />
<div class="overall-rating">
    (Average Rating <span id="avgrat"><?php echo $ratingRow['average_rating']; ?></span> Based on <span id="totalrat"><?php echo $ratingRow['rating_number']; ?></span>  rating)
</div>

rating.php

En este fichero obtenemos el ID del post y los puntos de votación enviados por AJAX. Comprobamos si los datos de votación existen en la tabla post_rating basándonos en el ID del post. Si existe, entonces modificamos el registro de la base de datos, pero en el caso de que no exista, tendremos que crear un nuevo registro. Al final, pasamos el resultado (si ha sido satisfactorio o no) en formato JSON.

include_once 'dbConfig.php';
if(!empty($_POST['ratingPoints'])){
    $postID = $_POST['postID'];
    $ratingNum = 1;
    $ratingPoints = $_POST['ratingPoints'];
    
    //Check the rating row with same post ID
    $prevRatingQuery = "SELECT * FROM post_rating WHERE post_id = ".$postID;
    $prevRatingResult = $db->query($prevRatingQuery);
    if($prevRatingResult->num_rows > 0):
        $prevRatingRow = $prevRatingResult->fetch_assoc();
        $ratingNum = $prevRatingRow['rating_number'] + $ratingNum;
        $ratingPoints = $prevRatingRow['total_points'] + $ratingPoints;
        //Update rating data into the database
        $query = "UPDATE post_rating SET rating_number = '".$ratingNum."', total_points = '".$ratingPoints."', modified = '".date("Y-m-d H:i:s")."' WHERE post_id = ".$postID;
        $update = $db->query($query);
    else:
        //Insert rating data into the database
        $query = "INSERT INTO post_rating (post_id,rating_number,total_points,created,modified) VALUES(".$postID.",'".$ratingNum."','".$ratingPoints."','".date("Y-m-d H:i:s")."','".date("Y-m-d H:i:s")."')";
        $insert = $db->query($query);
    endif;
    
    //Fetch rating deatails from database
    $query2 = "SELECT rating_number, FORMAT((total_points / rating_number),1) as average_rating FROM post_rating WHERE post_id = ".$postID." AND status = 1";
    $result = $db->query($query2);
    $ratingRow = $result->fetch_assoc();
    
    if($ratingRow){
        $ratingRow['status'] = 'ok';
    }else{
        $ratingRow['status'] = 'err';
    }
    
    //Return json formatted rating data
    echo json_encode($ratingRow);
}

Fuente: codexworld.com

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP