Plugin Development Fundamentals

WordPress Intermediate/Advanced

Chapter 5 · Plugin Development Fundamentals

add_action( 'init', ... ) has appeared twice already, unexplained, in WordPress Intermediate/Advanced 1 and 4. This is the chapter that formally opens it up — actions and filters, the single most important WordPress-specific concept a developer needs, and the mechanism behind every plugin WordPress Fundamentals 6 ever installed as a finished product.

What a Plugin Actually Is, Structurally

Just like a theme's style.css from WordPress Intermediate/Advanced 1, a plugin needs its own specially-formatted comment header — placed at the top of a PHP file inside wp-content/plugins/ — that WordPress parses to recognize and register it.

<?php /** * Plugin Name: My First Plugin * Description: A minimal example plugin. * Version: 1.0 * Author: Your Name */

Everything below that header is ordinary PHP — and a plugin does its actual work almost entirely by hooking functions onto actions and filters, rather than running code directly at the top level of the file.

Actions vs. Filters — The Core Distinction

ActionsFilters
Let you do something at a specific pointLet you modify a piece of data as it passes through
The hooked function's return value is ignoredThe hooked function must return a value — WordPress uses whatever comes back
Registered with add_action()Registered with add_filter()
Example: sending an email when a post is publishedExample: shortening every post excerpt to 20 words

add_action() — Doing Something

Every prior use of add_action( 'init', ... ) in this course follows the same shape: add_action( 'hook_name', 'function_to_run' ). WordPress calls your function at the exact moment it reaches that named point in its own execution.

<?php function add_footer_credit() { echo '<p>Built with a custom plugin.</p>'; } add_action( 'wp_footer', 'add_footer_credit' );

This directly reuses wp_footer() from WordPress Intermediate/Advanced 1 — that function's entire job is firing the wp_footer action, giving every plugin hooked into it a chance to run.

add_filter() — Modifying Data

<?php function custom_excerpt_length( $length ) { return 20; } add_filter( 'excerpt_length', 'custom_excerpt_length' );

WordPress calls this function while generating an excerpt, passing in the current word-count limit; the function returns 20, and that's the value WordPress actually uses.

The single most common filter mistake
A filter function that forgets to return a value doesn't leave the data unchanged — it silently replaces it with null, since a PHP function with no explicit return implicitly returns nothing. A filter hooked onto the_content that echoes debugging output instead of returning the (possibly modified) content will wipe out every post's body text entirely, with no error message anywhere pointing back to the cause.

A Small, Real Plugin — Both Mechanisms Together

<?php /** * Plugin Name: Reading Time Estimator * Description: Prepends an estimated reading time to every post. * Version: 1.0 */ // A filter: modifies the post content function prepend_reading_time( $content ) { if ( is_single() ) { $word_count = str_word_count( strip_tags( $content ) ); $minutes = ceil( $word_count / 200 ); $content = "<p>Estimated reading time: {$minutes} min</p>" . $content; } return $content; } add_filter( 'the_content', 'prepend_reading_time' ); // An action: logs when the plugin loads, does nothing visible function log_plugin_loaded() { error_log( 'Reading Time Estimator plugin loaded.' ); } add_action( 'init', 'log_plugin_loaded' );

This is genuinely the same category of tool WordPress Fundamentals 6 covered installing — the only difference is that this one was built from scratch, using nothing beyond ordinary PHP and the two hook functions this chapter just covered.

Priority — What Happens When Multiple Functions Hook the Same Point

add_action() and add_filter() both accept an optional priority argument (default 10) — lower numbers run earlier. Multiple plugins commonly hook the same action or filter, and priority is how their relative order is controlled when it matters.

add_action( 'wp_footer', 'add_footer_credit', 20 ); // runs later than the default

Hands-On Exercises

Exercise 1

A developer writes a filter function hooked to the_title that's supposed to append " — Read More" to every post title, but forgets to include a return statement. Explain exactly what visitors would see as a result.

📄 View solution
Exercise 2

Explain, using this chapter's own compare table, whether sending a notification email when a comment is posted should be built as an action or a filter, and why.

📄 View solution
Exercise 3

Explain what add_action( 'init', 'register_portfolio_post_type' ) from WordPress Intermediate/Advanced 4 is actually doing, now that this chapter has formally explained the mechanism behind it.

📄 View solution

Chapter 5 Quick Reference

  • A plugin file needs its own comment header block, parsed by WordPress, exactly like a theme's style.css
  • Actions (add_action()) — do something at a specific point; return value ignored
  • Filters (add_filter()) — modify a value as it passes through; the hooked function must return a value
  • A filter that forgets to return silently wipes the data to null — the single most common filter mistake
  • Priority (default 10, lower runs earlier) controls execution order when multiple functions hook the same point
  • Every register_post_type()/register_taxonomy() call from Chapter 4 was always this exact mechanism, hooked to init
  • Next chapter: The WordPress REST API