Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Your own plugin

A plugin is code that adds features to a site and does not depend on the theme. A custom post type, a form, a link to an external service must keep working after a change of design, so they are written in a plugin rather than in functions.php.

The plugin file

Create the wp-content/plugins/reading-time folder and in it a file of the same name:

<?php
/**
 * Plugin Name: Reading Time
 * Description: Shows the approximate reading time of a post.
 * Version: 1.0.0
 * Author: Anna Smith
 * Text Domain: reading-time
 */
// reading-time.php
 
defined('ABSPATH') || exit;
 
add_filter('the_content', function (string $content): string {
    if (!is_singular('post')) {
        return $content;
    }
 
    $minutes = max(1, (int) ceil(str_word_count(wp_strip_all_tags($content)) / 200));
 
    return '<p class="reading-time">Reading time: ' . $minutes . ' min</p>' . $content;
});

The plugin appears under "Plugins". Activate it — the reading time shows up before the text of every post.

Guarding against direct access

The defined('ABSPATH') || exit; line stops the file when it is opened directly by address rather than through WordPress. It goes at the top of every plugin file.

Activation and deactivation

// reading-time.php
 
register_activation_hook(__FILE__, function () {
    add_option('reading_time_speed', 200);
});
 
register_deactivation_hook(__FILE__, function () {
    // stop scheduled tasks
});

Activation runs once when the plugin is turned on — tables and default settings are created here.

Uninstalling

When a plugin is deleted from the dashboard, WordPress runs the uninstall.php file. It cleans up:

<?php
// uninstall.php
 
defined('WP_UNINSTALL_PLUGIN') || exit;
 
delete_option('reading_time_speed');

Paths and addresses

// reading-time.php
 
require_once plugin_dir_path(__FILE__) . 'includes/settings.php';
 
add_action('wp_enqueue_scripts', function () {
    wp_enqueue_style('reading-time', plugins_url('assets/style.css', __FILE__), [], '1.0.0');
});

plugin_dir_path() returns the folder path on disk, plugins_url() the file address for the browser.

Unique names

All plugins and the theme run in one PHP namespace. A function named get_settings() will almost certainly collide with someone else's. There are two ways to avoid that — a prefix or a namespace:

// reading-time.php
 
namespace ReadingTime;
 
function minutes(string $content): int
{
    return max(1, (int) ceil(str_word_count(wp_strip_all_tags($content)) / 200));
}
 
add_filter('the_content', __NAMESPACE__ . '\\prepend');
 
function prepend(string $content): string
{
    return '<p>' . minutes($content) . ' min</p>' . $content;
}

A prefix is added to the names of options, hooks and tables as well: reading_time_speed, not speed.

Must-use plugins

A file placed in the wp-content/mu-plugins folder is always active and cannot be turned off from the dashboard. Code the site must not run without is added this way.

Common mistake

Activation code runs only when the plugin is turned on. If you add table creation to it after the plugin is already active, the table does not appear. During development deactivate the plugin and activate it again, and for sites that already have the plugin keep a version number in the options and update the structure when it changes.

Thanks for reading!

Donate to the site — we work hard for you.