{"id":125358,"date":"2026-08-05T12:22:02","date_gmt":"2026-08-05T12:22:02","guid":{"rendered":"https:\/\/make.wordpress.org\/core\/?p=125358"},"modified":"2026-08-05T12:43:37","modified_gmt":"2026-08-05T12:43:37","slug":"the-notify_post_author-filter-now-has-the-final-say-on-post-author-notifications","status":"publish","type":"post","link":"https:\/\/make.wordpress.org\/core\/2026\/08\/05\/the-notify_post_author-filter-now-has-the-final-say-on-post-author-notifications\/","title":{"rendered":"The\u00a0notify_post_author\u00a0filter now has the final say on post author notifications"},"content":{"rendered":"<p class=\"wp-block-paragraph\">WordPress 7.1 changes when\u00a0<code>wp_new_comment_notify_postauthor()<\/code>\u00a0checks a comment\u2019s approval status: the check now happens\u00a0<em>before<\/em>\u00a0the\u00a0<code>notify_post_author<\/code>\u00a0<span tabindex='0' class='glossary-item-container'>filter<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Filter<\/span> <span class='glossary-item-description'>Filters are one of the two types of Hooks <a href=\"https:\/\/codex.wordpress.org\/Plugin_API\/Hooks\">https:\/\/codex.wordpress.org\/Plugin_API\/Hooks<\/a>. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.<\/span><\/span><\/span> is applied, rather than after. As a result, the filter receives an accurate default value, and its return value fully determines whether a notification is sent. See\u00a0<a href=\"https:\/\/core.trac.wordpress.org\/ticket\/64217\">#64217<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Previous behavior<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The filter received a default derived only from the\u00a0<code>comments_notify<\/code>\u00a0option (or the\u00a0<code>wp_notes_notify<\/code>\u00a0option for notes). The comment\u2019s approval status was checked\u00a0<em>after<\/em>\u00a0the filter ran, which had two consequences:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The filter received a misleading default of\u00a0<code>true<\/code>\u00a0for unapproved comments whenever the option was enabled, even though no notification would be sent.<\/li>\n\n\n\n<li>Returning\u00a0<code>true<\/code>\u00a0from the filter could not force a notification for an unapproved comment \u2013 the return value was silently discarded.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">New behavior in 7.1<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The approval status is now incorporated into the default value passed to the filter, and the filter\u2019s return value is final:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The default is\u00a0<code>false<\/code>\u00a0for comments that are not approved, including those held in moderation, marked as spam, or trashed.<\/li>\n\n\n\n<li>The default for approved comments continues to follow the\u00a0<code>comments_notify<\/code>\u00a0option, and the default for notes continues to follow the\u00a0<code>wp_notes_notify<\/code>\u00a0option regardless of approval status.<\/li>\n\n\n\n<li>Returning\u00a0<code>true<\/code>\u00a0from the filter now sends the notification, even for an unapproved comment.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Two smaller changes ship alongside this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The default passed to the filter is now always a strict boolean. Previously the raw option value (for example the string\u00a0<code>'1'<\/code>) could be passed through, so callbacks that strictly compare the incoming\u00a0<code>$maybe_notify<\/code>\u00a0value should compare against\u00a0<code>true<\/code>\/<code>false<\/code>.<\/li>\n\n\n\n<li>When the passed comment ID does not resolve to a valid comment, the function now returns\u00a0<code>false<\/code>\u00a0immediately without applying the filter. Previously, the filter still fired in this case.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Who is affected<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Sites or plugins using a callback such as\u00a0<code>__return_true<\/code>\u00a0on\u00a0<code>notify_post_author<\/code>\u00a0to force notifications will now also receive emails for comments held in moderation, marked as spam, or trashed. If that is not desired, the callback should check the comment\u2019s approval status:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: php; title: ; notranslate\" title=\"\">\nadd_filter(\n\t'notify_post_author',\n\tfunction ( $maybe_notify, $comment_id ) {\n\t\t$comment = get_comment( $comment_id );\n\n\t\t\/\/ Only force notifications for approved comments.\n\t\tif ( $comment &amp;&amp; '1' === $comment-&gt;comment_approved ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn $maybe_notify;\n\t},\n\t10,\n\t2\n);\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Callbacks that only\u00a0<em>suppress<\/em>\u00a0notifications (returning\u00a0<code>false<\/code>) are unaffected, as are sites that do not filter\u00a0<code>notify_post_author<\/code>\u00a0at all.<\/p>\n\n\n\n<p class=\"has-text-align-right wp-block-paragraph\"><em>Props to <a href=\"https:\/\/profiles.wordpress.org\/milana_cap\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>milana_cap<\/a> for peer review.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n<p class=\"o2-appended-tags\"><a href=\"https:\/\/make.wordpress.org\/core\/tag\/7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>7-1<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes-7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes-7-1<\/a><\/p><nav class='o2-post-footer-actions'><ul class='o2-post-footer-action-row'><li class='o2-post-footer-action'><a href=\"https:\/\/login.wordpress.org\/?redirect_to=https%3A%2F%2Fmake.wordpress.org%2Fcore%2F2026%2F08%2F05%2Fthe-notify_post_author-filter-now-has-the-final-say-on-post-author-notifications%2F%23respond&#038;locale=en_US\" title=\"Login to Reply\"  class=\"genericon  genericon-reply\"  data-action=\"login-to-reply\"  data-actionstate=\"default\" >Login to Reply<\/a><\/li><\/ul><div class='o2-post-footer-action-likes'><\/div><ul class='o2-post-footer-action-row'><\/ul><\/nav>","protected":false},"excerpt":{"rendered":"<p>WordPress 7.1 changes when\u00a0wp_new_comment_notify_postauthor()\u00a0checks a comment\u2019s approval status: the check now happens\u00a0before\u00a0the\u00a0notify_post_author\u00a0filterFilter Filters are one of the two types of Hooks https:\/\/codex.wordpress.org\/Plugin_API\/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have [&hellip;]<\/p>\n","protected":false},"author":10464658,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_seo_schema_type":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1175],"tags":[5885,1443,5894],"class_list":["post-125358","post","type-post","status-publish","format-standard","hentry","category-general","tag-7-1","tag-dev-notes","tag-dev-notes-7-1","mentions-milana_cap","author-adamsilverstein"],"revision_note":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2AvED-wBU","jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125358","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/users\/10464658"}],"replies":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/comments?post=125358"}],"version-history":[{"count":2,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125358\/revisions"}],"predecessor-version":[{"id":125369,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/125358\/revisions\/125369"}],"wp:attachment":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/media?parent=125358"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/categories?post=125358"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/tags?post=125358"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}