Skip to content

Update email provider token-message hooks - #897

Open
joemaller wants to merge 5 commits into
WordPress:masterfrom
joemaller:email_filters
Open

Update email provider token-message hooks#897
joemaller wants to merge 5 commits into
WordPress:masterfrom
joemaller:email_filters

Conversation

@joemaller

@joemaller joemaller commented Jun 7, 2026

Copy link
Copy Markdown

What?

The primary purpose of this PR is to provide the $token to the email provider's subject filter. It also brings consistency to the shape of Two Factor's email provider token-message hook arguments, and standardizes the namespaces used by those filters. Includes tests and documentation.

Fixes: #898

Why?

Many services now include the login token in their email subject lines like "Your login code is 123456". This improves user-experience and speeds MFA logins.

Previously, the email subject filter did not have access to$token and its arguments did not match the shape of the message filter arguments. Developers wanting to include the token in email subjects had to use clumsy, fragile workarounds.

This PR adds (renames) two hooks:

  • two_factor_email_token_subject
  • two_factor_email_token_message

This PR deprecates two existing hooks:

  • two_factor_token_email_subject
  • two_factor_token_email_message

New hook names provide a clean pathway for changing the signature of two_factor_token_email_subject without breaking existing functionality. The new filter adds a $token argument to match the shape of two_factor_token_email_message. This makes it very easy for developers to include $token in email subject lines.

How?

  • The arguments to both the two_factor_email_token_subject and two_factor_email_token_message filters are now symmetrical: $subject|$message, $token, $user_id.
  • Old hooks have been deprecated for backwards compatibility.
  • The new filters have been added to readme.txt. They were not previously documented.
  • Added tests to cover both the new and deprecated filters.

Use of AI Tools

AI assistance: Yes
Tool(s): Opencode, browsers
Model(s): grok 4.3, gemini-3.1-pro-preview
Used for: Architectural suggestions, consistency and style-matching with existing code, and code review/QA.

Testing Instructions

Tests covering the changes were added.
Add this line to a theme with Two Factor installed to add the token to the email subject.

add_filter( 'two_factor_email_token_subject', function( $subject, $token ) {
    return "{$token} is your login code";
}, 10, 2 );

Changelog Entry

Change - Added $token to the token-email subject filter.
Deprecated - two_factor_token_email_subject and two_factor_token_email_message. Replaced with consistently named two_factor_email_token_* filters.

Open WordPress Playground Preview

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @christianc1.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Unlinked contributors: christianc1.

Co-authored-by: joemaller <joemaller@git.wordpress.org>
Co-authored-by: masteradhoc <masteradhoc@git.wordpress.org>
Co-authored-by: r-a-y <r-a-y@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Two_Factor_Email provider’s token email subject/message filter hooks to expose the $token in the subject filter, introduce consistently named replacement hooks (two_factor_email_token_*), and deprecate the legacy two_factor_token_email_* hooks while adding corresponding tests and documentation updates.

Changes:

  • Deprecates two_factor_token_email_subject / two_factor_token_email_message and introduces two_factor_email_token_subject / two_factor_email_token_message with symmetric argument shapes.
  • Adds PHPUnit coverage for both deprecated and new hooks.
  • Documents the new hooks in readme.txt.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
providers/class-two-factor-email.php Adds new two_factor_email_token_* filters and wraps legacy hooks in apply_filters_deprecated().
tests/providers/class-two-factor-email.php Adds tests validating subject/body filtering through both deprecated and new hooks.
readme.txt Documents the new email token subject/body filters (and minor whitespace cleanup nearby).
Comments suppressed due to low confidence (1)

providers/class-two-factor-email.php:343

  • The deprecation notice version for this hook doesn't match the @deprecated 0.17.0 tag above. apply_filters_deprecated() should use the version where the hook was deprecated so the emitted message is accurate.
		$message = apply_filters_deprecated( 'two_factor_token_email_message', array( $message, $token, $user->ID ), '0.11.0', 'two_factor_email_token_message' );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread providers/class-two-factor-email.php Outdated
Comment on lines +449 to +451
function () {
return 'New Subject';
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding $subject to the callback triggers a phpcs warning:

 451 | WARNING | The method parameter $subject is never used (Generic.CodeAnalysis.UnusedFunctionParameter.Found)

So line 449 would actually need to be:

   	function ( $subject ) {  // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found 

Similar to

function two_factor_filter_enabled_providers_for_user( $enabled, $user_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Filter signature includes user_id, but this site-wide restriction only needs the enabled providers list.

Comment thread readme.txt Outdated

@masteradhoc masteradhoc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much @joemaller for the PR, we appreciate it!

The missing $token in the subject filter is a real gap, and the use case (putting the code in the subject line) is a good one!

That said, I'd rather we avoid the deprecation and rename here, and just append $token as the last argument to the existing filter:

This is fully backwards compatible, so nothing existing changes behaviour. It gets us the actual goal of the PR (developers can put the token in the subject) in one line, with no new hook names to maintain.

I know the argument order then doesn't line up with two_factor_token_email_message ($subject, $user_id, $token vs $message, $token, $user_id), and that isn't pretty. But inconsistent argument order is a documentation problem, whereas deprecating a public hook is a permanent maintenance obligation — in practice we'd be carrying both names indefinitely. Core makes this same trade-off regularly for the same reason.

The two_factor_token_email_message rename is the part I'd most likely drop from this PR. I agree two_factor_email_token_* is the more consistent namespace given two_factor_email_token_ttl and _length, but I don't think that's worth spending a deprecation on.

What do you think @georgestephanis ?

@joemaller Would you be able to update the PR along those lines when you get a chance, and pick up the Copilot review feedback and test adjustments at the same time? Happy to take another look once it's pushed.

@joemaller

joemaller commented Jul 31, 2026

Copy link
Copy Markdown
Author

Hi @masteradhoc, thanks for the review.

Yes, a one-line change to append $token would solve the immediate problem, but it would also lock in an unfortunate, permanent inconsistency. Since Two Factor is pre-1.0, this felt like the right moment for a cleaner solution.

Some of the considerations behind the proposed changes:

  • Two Factor is 0.x By definition, there should be no expectation that pre-1.0 APIs are locked down or fully resolved. This is the window for fixing inconsistencies which would be breaking changes later.

  • Minor deprecation beats permanent inconsistency - Appending $token to the subject filter would result in two related filters with shuffled argument order: $subject, $user->ID, $token vs. $message, $token, $user->ID. Mismatches like that lead to future bugs and frustrate developers.

  • Filter names match provider - All other filters in providers/*.php follow their provider context. Last year, commits 01cfb60 and 33f0060 renamed and deprecated two_factor_token_ttl -> two_factor_email_token_ttl and two_factor_token_length -> two_factor_email_token_length for consistency and "to avoid confusion about the token type". The two filters renamed by my proposed changes are the only remaining outliers.

  • Existing hooks are undocumented and barely used - The two_factor_token_email_subject and two_factor_token_email_message filters were added 6 years ago by @christianc1 but never documented. Searching GitHub, they barely show any usage:

    (We could almost skip the deprecation vs. documentation argument completely and just ask @carstingaxion and @r-a-y to please update their code.)

  • Deprecation is documentation - apply_filters_deprecated explains itself. Future users never have to care about deprecated hook names and future documentation authors won't have to write around them.

There is an expectation that Two Factor will eventually land in WordPress core, many of us have standardized on it for that reason. Feature plugins exist to get the public surface as clean as possible before moving to core. A future merge would also be a natural opportunity to drop any lingering deprecations.

Even if the old hooks stick around forever, this cognitive and aesthetic improvement is worth the small cost. Millions of sites will likely use this, let's give those developers an elegant solution.

@r-a-y

r-a-y commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

(We could almost skip the deprecation vs. documentation argument completely and just ask @carstingaxion and @r-a-y to please update their code.)

Thanks for letting me know about the proposed change.

In the past, the two-factor plugin has removed PHP class methods outright without deprecating or changed CSS selectors in the markup and I've had to adjust my code to fix some issues so I appreciate the ping.

@christianc1

Copy link
Copy Markdown
Contributor

@joemaller Just noting that a public search of Github (AFAIK) doesn't surface private repositories, so usage signals derived by that method should be taken with a grain of salt. Also, kicking myself that I didn't see the use case you described here 6 years ago when I contributed the filter, it's a great idea for U/X.

@masteradhoc

Copy link
Copy Markdown
Collaborator

Thank you @joemaller for your feedback. While we check this can you fix those PHP lint issues?

FILE: tests/providers/class-two-factor-email.php
--------------------------------------------------------------------------------
FOUND 5 ERRORS AFFECTING 5 LINES
--------------------------------------------------------------------------------
 448 | ERROR | Inline comments must end in full-stops, exclamation marks, or
     |       | question marks (Squiz.Commenting.InlineComment.InvalidEndChar)
 464 | ERROR | Inline comments must end in full-stops, exclamation marks, or
     |       | question marks (Squiz.Commenting.InlineComment.InvalidEndChar)
 493 | ERROR | Inline comments must end in full-stops, exclamation marks, or
     |       | question marks (Squiz.Commenting.InlineComment.InvalidEndChar)
 498 | ERROR | Inline comments must end in full-stops, exclamation marks, or
     |       | question marks (Squiz.Commenting.InlineComment.InvalidEndChar)
 514 | ERROR | Inline comments must end in full-stops, exclamation marks, or
     |       | question marks (Squiz.Commenting.InlineComment.InvalidEndChar)
--------------------------------------------------------------------------------

Please make sure your code passes phpstan v5 - which is what we're aming for in the next release :)

@joemaller

Copy link
Copy Markdown
Author

@masteradhoc all linting errors and Copilot suggestions resolved. Thank you for merging master back onto this.

@joemaller

Copy link
Copy Markdown
Author

@christianc1, No, search doesn't include private repos, I should've left the laughing emoji in that point. But I don't think those results are an entirely meaningless metric.

Also I tagged you specifically since you wrote the original and there was a good chance you all were using it internally (in private repos). Thanks for adding the filter in here in the first place!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Access Token from Email Provider subject filters

5 participants