Adding estimated time to read an article in Laravel
Categorized as Laravel
If you’re wondering how to do that, the short answer is here: we are going to use one private method and Laravel Accessor. Don’t be afraid, it’s pretty simple.
First off, we’re going to count seconds and minutes to read using this formula:
$minutes = (int) floor($wordCount / 200);
$seconds = (int) floor($wordCount % 200 / (200 / 60));
Let’s make a whole function using that formula and put in into our Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Article extends Model
{
...
/**
* Returns an estimated reading time in a string
* @param string $content the content to be read
* @param int $wpm
* @return string estimated read time eg. 1 min or 31 sec
**/
private function getEstimateReadingTime($content, $wpm = 200) {
$wordCount = str_word_count(strip_tags($content));
$minutes = (int) floor($wordCount / $wpm);
$seconds = (int) floor($wordCount % $wpm / ($wpm / 60));
if ($minutes === 0) {
return "{$seconds} sec read";
} else {
return "{$minutes} min read";
}
}
}
You can also use a slightly advanced method, showing pluralized minutes and seconds. Don’t forget to add the Str::helper
support to your Model:
use Illuminate\Support\Str;
/**
* Returns an estimated reading time in a string
* @param string $content the content to be read
* @param int $wpm
* @return string estimated read time eg. 1 minute, 30 seconds
**/
private function getEstimateReadingTime($content, $wpm = 200) {
$wordCount = str_word_count(strip_tags($content));
$minutes = (int) floor($wordCount / $wpm);
$seconds = (int) floor($wordCount % $wpm / ($wpm / 60));
if ($minutes === 0) {
return $seconds." ".Str::of('second')->plural($seconds);
} else {
return $minutes." ".Str::of('minute')->plural($minutes);
}
}
Now we add an Accessor, which allows us to add (or change) Eloquent attribute values on model instances:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Article extends Model
{
...
private function getEstimateReadingTime($content, $wpm = 200) {
...
}
protected function timeToRead(): Attribute {
return Attribute::make(
get: function ($value, $attributes) {
$value = $this->getEstimateReadingTime($attributes['body']);
return $value;
}
);
}
Finally, we can update our template file to show the estimated reading time:
@foreach($article as $item)
...
{{ $item->time_to_read }}
...
@endforeach