Estimate Article Reading Time with a Simple PHP Function

Estimate Article Reading Time with a Simple PHP Function

Reading time is an estimate: count the words, divide by an assumed reading speed, and round up to the next minute.

A useful default for English non-fiction is 238 words per minute. That figure comes from a review of reading-rate studies, but it is not a rule for every reader. Technical writing, unfamiliar subjects, and code usually take longer.

Calculate the reading time

The core function should receive plain text:

function reading_time_in_minutes(
    string $text,
    int $wordsPerMinute = 238,
): int {
    if ($wordsPerMinute < 1) {
        throw new InvalidArgumentException('Words per minute must be greater than zero.');
    }

    preg_match_all(
        "/[\p{L}\p{N}]+(?:['’\-][\p{L}\p{N}]+)*/u",
        $text,
        $matches,
    );

    $words = count($matches[0]);

    if ($words === 0) {
        return 0;
    }

    return (int) ceil($words / $wordsPerMinute);
}

Usage is straightforward:

$minutes = reading_time_in_minutes($articleText);

echo $minutes === 1
    ? '1 minute read'
    : "{$minutes} minutes read";

The explicit integer cast matters because ceil() returns a float. Without it, a function with an int return type can fail when strict typing is enabled.

Do not count raw HTML

Passing article HTML directly to the function also counts tag names and attributes. Convert it to text first.

For controlled HTML produced by your own editor or CMS, a small conversion can be enough:

function article_html_to_text(string $html): string
{
    $text = preg_replace('/<[^>]+>/', ' ', $html) ?? '';

    return html_entity_decode(
        $text,
        ENT_QUOTES | ENT_HTML5,
        'UTF-8',
    );
}

$text = article_html_to_text($article->content);
$minutes = reading_time_in_minutes($text);

Replacing tags with spaces preserves the boundary between adjacent paragraphs. strip_tags() alone can join text from neighbouring elements into one word.

This helper is a text extractor, not an HTML sanitizer. Sanitize untrusted HTML before storing or displaying it.

Why not use str_word_count()?

str_word_count() is convenient, but PHP documents two important limits:

  • its definition of a word depends on the current locale;
  • multibyte locales are not supported.

That makes it unreliable for accented text and many non-English languages. The Unicode pattern above counts sequences of letters and numbers while keeping common apostrophes and hyphens inside a word.

It is still an estimate. A code-heavy tutorial and a short news article with the same word count will not take the same time to read. The function provides a consistent label, not a measurement of an individual reader.

Source