Just like the core WordPress files, the user shouldn’t modify plugin files. Their changes will be overridden on the next plugin update. This is the reason why hooks exist in the first place, and plugins are no different.
The hallmark of a great plugin is in its hooks. You should always try to predict what data your users might want to filter or where they might want to run actions. The most important and commonly used settings should be exposed in the UI (e.g., using the Settings API), but some requirements are just so niche that displaying them in the admin panel would only clutter it. Nevertheless, that doesn’t make them any less valid.
Trust me when I say that you’re going to lose your mind if you ever have to modify a plugin’s behavior, only to discover that there’s no hook to actually do it. With that in mind, let’s make our tech-minded users love us by making our plugin extensible.
function pgn_calculate_reading_time( $content ) {
$avg_words_per_minute = 250;
$avg_words_per_minute = apply_filters( 'pgn_words_per_minute', $avg_words_per_minute );
$word_count = str_word_count( strip_tags( $content ) );
$reading_time = $word_count / $avg_words_per_minute;
$reading_time = apply_filters(
'pgn_reading_time',
$reading_time,
$word_count,
$avg_words_per_minute
);
return ceil( $reading_time );
}
function pgn_add_snippet_to_post_content( $content ) {
if ( ! is_single() || ! is_main_query() || ! in_the_loop() ) {
return $content;
}
$reading_time_text = get_option( 'pgn_reading_time_text' );
if ( empty( $reading_time_text ) ) {
$reading_time_text = 'Reading time'; // Default
}
$reading_time = pgn_calculate_reading_time( $content );
$display_html = '<div class="pgn-reading-time">' . $reading_time_text . ': ' . $reading_time . ' min</div>';
$display_html = apply_filters( 'pgn_display_html', $display_html, $reading_time_text, $reading_time );
return $display_html . $content;
}As you can see, we’ve added 3 filters:
- pgn_words_per_minute (which should probably also be a setting. “Also” and not “instead” because filters provide programmatic control, i.e., returning a different value depending on the post)
- pgn_reading_time
- pgn_display_html
Our users (or any extending plugins) can now hook into those filters with add_filter() and modify the data. We didn’t add any actions because, in this particular case, I don’t see any legitimate reason/place to do so.
Please note that, similar to other code snippets in this guide, the above code is not production ready. You should always check that the values returned by the filters are what you expect them to be. For example – for words per minute, you’d check that the value is a positive integer, and if it isn’t – you’d default to 250 and throw an error (using wp_trigger_error() or a custom function checking for ‘WP_DEBUG’ if you want to support <6.4).