Ever wanted to add a small feature to a WordPress website without installing another plugin?
Maybe it's a reading-time indicator, a custom notice, or something specific to your client's project.
The good news? You don't need a complicated framework to get started.
WordPress has a powerful system of hooks that lets you extend its functionality with just a few lines of PHP.
In this tutorial, we'll build a tiny plugin that automatically displays an estimated reading time above blog posts.
What you'll learn:
- How WordPress plugins work
- How to create a plugin from scratch
- How to use the
the_contentfilter - How to calculate reading time with PHP
- How to safely display custom content
And the best part? We won't need any third-party dependencies.
First, a quick hello! 👋
We're Raddito, a web design and development team specializing in WordPress, WooCommerce, and modern website-building workflows.
This is our first post on DEV Community!
We're here to share practical development tutorials, lessons from building websites, and solutions to common WordPress challenges.
Let's start by building something useful.
Step 1: Understand how WordPress plugins work
A WordPress plugin is essentially PHP code that extends the behavior of a WordPress website.
Instead of modifying WordPress core files, you connect your code to WordPress using hooks.
There are two main types:
Actions: Run your code when something happens.
Filters: Allow you to modify data before WordPress uses or displays it.
For our reading-time feature, we'll use a filter called the_content.
This filter gives us access to post content before WordPress displays it.
That means we can add our reading-time indicator without editing individual blog posts.
Step 2: Create your plugin folder
Open your WordPress installation and navigate to:
wp-content/plugins/
Create a new folder named:
raddito-reading-time
Inside that folder, create a PHP file:
raddito-reading-time.php
Your directory structure should look like this:
wp-content/
└── plugins/
└── raddito-reading-time/
└── raddito-reading-time.php
Simple, right?
Now let's make WordPress recognize it.
Step 3: Add the plugin header
Open raddito-reading-time.php and add:
<?php
/**
* Plugin Name: Raddito Reading Time
* Description: Shows an estimated reading time on single blog posts.
* Version: 1.0.0
* Author: Raddito
* Text Domain: raddito-reading-time
*/
This header tells WordPress that the PHP file is a plugin.
Next, add a small security check:
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
This prevents the plugin file from being executed directly outside WordPress.
Now go to your WordPress dashboard:
Plugins → Installed Plugins
You should see Raddito Reading Time in the list.
Don't activate it just yet. We still need to add the actual functionality.
Step 4: Calculate reading time
Reading time is usually estimated by dividing the number of words by an average reading speed.
For this example, we'll use 200 words per minute.
The formula is:
Reading time = Total words / 200
So a 600-word article would have an estimated reading time of 3 minutes.
Let's add a function below our existing code:
function raddito_add_reading_time( $content ) {
if (
! is_singular( 'post' ) ||
! in_the_loop() ||
! is_main_query()
) {
return $content;
}
$post_id = get_the_ID();
if ( ! $post_id ) {
return $content;
}
$raw_content = get_post_field(
'post_content',
$post_id,
'raw'
);
$plain_text = wp_strip_all_tags(
strip_shortcodes( $raw_content )
);
$word_count = str_word_count( $plain_text );
$minutes = max(
1,
(int) ceil( $word_count / 200 )
);
$label = sprintf(
/* translators: %d: estimated reading time in minutes. */
__( '%d min read', 'raddito-reading-time' ),
$minutes
);
return '<p class="raddito-reading-time">' .
esc_html( $label ) .
'</p>' .
$content;
}
Let's break down what's happening.
1. Check the page context
if (
! is_singular( 'post' ) ||
! in_the_loop() ||
! is_main_query()
) {
return $content;
}
We only want the reading-time indicator to appear within the main content of individual blog posts.
This helps prevent it from appearing in unrelated content areas.
2. Get the original post content
$raw_content = get_post_field(
'post_content',
$post_id,
'raw'
);
We use the original content rather than the filtered content to avoid counting HTML generated by other plugins.
3. Remove unnecessary markup
$plain_text = wp_strip_all_tags(
strip_shortcodes( $raw_content )
);
We remove HTML and registered shortcodes so they don't distort our estimate.
4. Calculate the reading time
$word_count = str_word_count( $plain_text );
$minutes = max(
1,
(int) ceil( $word_count / 200 )
);
The ceil() function rounds up, while max() ensures that even very short posts show at least one minute.
5. Prepare the output safely
We use WordPress translation and escaping functions to create the final label.
This is an important habit when writing WordPress plugins: escape dynamic content when outputting it into HTML.
Step 5: Connect the function to WordPress
We have our function, but WordPress doesn't know when to run it.
Add this line at the bottom of your plugin:
add_filter(
'the_content',
'raddito_add_reading_time'
);
That's it!
Whenever WordPress processes post content through this filter, our function can add the reading-time label.
Now activate your plugin and open a published blog post.
You should see something like:
3 min read
Followed by your normal article content.
No extra dependencies. No page builder required.
Step 6: Make the reading-time label look better
Our plugin works, but a little CSS can improve the appearance.
Add the following CSS through your theme's custom CSS area or stylesheet:
.raddito-reading-time {
display: inline-block;
margin-bottom: 1rem;
padding: 0.35rem 0.75rem;
background: #f1f5f9;
color: #334155;
border-radius: 6px;
font-size: 0.875rem;
font-weight: 600;
line-height: 1.5;
}
Now the reading-time label will look more like a small badge.
You can adjust the colors, spacing, and typography to match your website's design system.
Step 7: Test your plugin
Before using custom functionality on a production website, test it.
Here are a few things worth checking:
- Open a short article and confirm it displays at least
1 min read. - Open a longer article and verify that the estimate changes.
- Visit a standard WordPress page and confirm the label doesn't appear.
- Check your blog archive and make sure excerpts are unaffected.
- Disable the plugin and confirm the label disappears.
Also, keep in mind that str_word_count() is most appropriate for English-language content. Sites using languages without conventional space-separated words will need a different counting strategy.
Our estimate also doesn't include words generated dynamically by shortcodes or blocks.
For a simple English-language blog, though, this is a useful starting point.
What did we actually learn?
We built a working WordPress plugin using one PHP file and a WordPress filter.
Along the way, we explored a few important development concepts:
Separation of concerns: We added functionality without modifying the theme or WordPress core.
Hooks: We learned how to extend WordPress behavior through filters.
Context-aware logic: We limited the feature to the content where it belongs.
Safe output: We used WordPress escaping functions before displaying generated text.
These principles become even more valuable as you work on larger WordPress projects.
Where could we take this next?
Once you're comfortable with this basic plugin, you could extend it further.
For example, you could add an admin setting to change the words-per-minute value, support custom post types, or create a Gutenberg block for displaying the reading time wherever you want.
You could also make the word-counting logic more suitable for multilingual websites.
Small projects like this are a great way to become familiar with WordPress development.
Final thoughts
At Raddito, we work with WordPress regularly, and one lesson keeps coming up: the best solution isn't always the one with the most features.
Sometimes, a small piece of well-structured code is exactly what a project needs.
This was our first tutorial here on DEV, and we're looking forward to sharing more practical lessons about WordPress, development workflows, website performance, and building better experiences for users.
Now we're curious:
What's one small WordPress feature you've built yourself instead of installing a plugin?
Share it in the comments. We'd love to hear about it!
About Raddito
We're a WordPress web design and development team helping businesses build fast, functional, and easy-to-manage websites.
Explore our work: Raddito.agency
Explore our web templates: Raddito.net
Useful documentation:
Top comments (0)