Victor Sokoliuk
Victor Sokoliuk

Reputation: 445

How to display half star when average non-integer (Star rating)

I use this code to display the average rating with half-filled stars (if the average rating is not an integer). It works great.

<?php
$stars   = '';
for ( $i = 1; $i <= $avrating + 1; $i++ ) {
$width = intval( $i - $avrating > 0 ? 20 - ( ( $i - $avrating ) * 20 ) : 20 );
if ( 0 === $width ) {
    continue;
}
    if($avrating < 5){
        $stars .= '<span style="overflow:hidden; width:' . $width . 'px" class="dashicons dashicons-star-filled"></span>';
        if ( $i - $avrating > 0 ) {
            $stars .= '<span style="overflow:hidden; position:relative; left:-' . $width .'px;" class="dashicons dashicons-star-empty"></span>'; 
        }
    }
}
if($avrating >= 5){
    for ($i = 1; $i <= 5; $i++) {

        echo '<span style="overflow:hidden;" class="dashicons dashicons-star-filled"></span>';
    }
  }
  echo $stars;
?> 

However, in this case, not all stars are displayed. For example, if the rating is 3.5, then 4 stars are displayed, the fourth is half full. Here is the image: 1: https://i.sstatic.net/2aoGx.png But I need all five stars to be displayed: the last empty fourth is half filled (if the rating is 3.5, for example) and the first three are full. I can bring out all the stars. With this code:

<?php
$stars = '';

for ( $i = 1; $i <= 5 ; $i ++ ) {
    if ( $i <= $avrating ) {
        $stars .= '<span class="dashicons dashicons-star-filled"></span>';
    } else {
        $stars .= '<span class="dashicons dashicons-star-empty"></span>';
    }
}                                   
echo   $stars;
?>  

But as a result, I naturally do not achieve the result. Here's what I get: enter image description here

You see, there is no half in the fourth star. I think it is possible to combine these two code fragments, but my knowledge is not enough how to do it. Or maybe this is not possible at all. Please help solve this problem.

Upvotes: 0

Views: 635

Answers (2)

Jeto
Jeto

Reputation: 14927

I'd make a simple function which returns the filling level of a given star against a given rating:

<?php
function getStarClass(int $starPosition, float $rating): string
{
  if ($starPosition <= $rating) {
    return 'filled';
  }
  if ($starPosition - $rating < 1) {
    return 'half-filled';
  }
  return 'empty';
}

$avrating = 3.5;
?>

<?php for ($star = 1; $star <= 5; $star++): ?>
  <span class="dashicons dashicons-star-<?= getStarClass($star, $avrating) ?>"></span>
<?php endfor ?>

Note that I'm also using PHP's alternative syntax to display the HTML, as I believe it's a better fit for that purpose, but that's entirely optional.

Upvotes: 2

Nigel Ren
Nigel Ren

Reputation: 57131

You can add an extra clause which checks if the loop is greater than the rating but less than the next rating as a half start rating...

$stars = '';
for ( $i = 1; $i <= 5 ; $i ++ ) {
    if ( $i <= $avrating ) {
        $stars .= '<span class="dashicons dashicons-star-filled"></span>';
    } elseif ( $i < $avrating + 1 && $i > $avrating ) {
        $stars .= '<span class="dashicons dashicons-star-half"></span>';
    } else {
        $stars .= '<span class="dashicons dashicons-star-empty"></span>';
    }
}  

you could also reduce a lot of the repeated boiler plate HTML by adding it as parts...

$stars = '';
for ( $i = 1; $i <= 5 ; $i ++ ) {
    $stars .= '<span class="dashicons dashicons-star-';
    if ( $i <= $avrating ) {
        $stars .= 'full';
    } elseif ( $i < $avrating + 1 && $i > $avrating ) {
        $stars .= 'half';
    } else {
        $stars .= 'empty';
    }
    $stars .= '"></span>';
}  

Upvotes: 2

Related Questions