A filter receives a value, may change it, and must return it. WordPress then uses whatever comes back.
<?php
add_filter("the_title", function (string $title): string {
return $title . " ✔";
});
The golden rule: always return
If your filter forgets to return, the value becomes null, and the content disappears.
<?php
add_filter("demo_text", function (string $text): string {
$text = trim($text);
return $text . "!";
});
echo apply_filters("demo_text", " hello ");
hello!
Filtering the post content
the_content is the most common filter. This one adds a notice below every post’s content.
<?php
function myplugin_add_notice(string $content): string
{
if (!is_singular("post") || !in_the_loop() || !is_main_query()) {
return $content; // always return the original when you do nothing
}
return $content . '<p class="notice">Thanks for reading!</p>';
}
add_filter("the_content", "myplugin_add_notice");
echo has_filter("the_content", "myplugin_add_notice") !== false ? "filter registered" : "missing";
filter registered
The three checks make sure that you change only the main post content on a single post page, and not excerpts, widgets or other places that also call the_content.
Your own filter
Let other code change your values.
<?php
function myshop_price(float $price): string
{
$price = (float) apply_filters("myshop_price_value", $price);
return "Rs. " . number_format($price, 2);
}
add_filter("myshop_price_value", fn(float $p) => $p * 0.9); // a 10% sale
echo myshop_price(1000);
Rs. 900.00
Several arguments
<?php
add_filter("myshop_label", function (string $label, int $count): string {
return $count === 1 ? $label : $label . "s";
}, 10, 2);
echo apply_filters("myshop_label", "item", 3);
items
Useful filters
| Filter | Changes |
|---|---|
the_content | Post content before printing |
the_title | Post title |
excerpt_length, excerpt_more | Excerpt settings |
body_class, post_class | CSS class lists |
upload_mimes | Allowed upload file types |
wp_mail_from | Sender address |
document_title_parts | Parts of the <title> |
template_include | Which template file to load |
pre_get_posts (action that edits the query) | The main query |
Filters vs actions
| Filter | Action | |
|---|---|---|
| Returns a value | Yes, required | No |
| Purpose | Change data | Do something |
| Typical mistake | Forgetting return | Doing slow work on every request |
Type safety
A filter callback receives whatever the caller passed. Another plugin may have changed it to something unexpected. Be defensive.
<?php
add_filter("demo_value", function (mixed $value): mixed {
return is_string($value) ? strtoupper($value) : $value;
});
echo apply_filters("demo_value", "safe") . " / ";
var_dump(apply_filters("demo_value", ["not", "a string"]) === ["not", "a string"]);
SAFE / bool(true)
Echoing inside a filter
null.