Sending emails in WordPress is something really simple. Yet, a lot of users, admins and even web designers and developers face troubles while triggering the mailer.

We are not talking about that today, but I really can’t see the point of installing “SMTP mailers” in WordPress – the wp_mail() function alone offers any developer the possibility of configuring the PHPmailer definitions, using the hook phpmailer_init.

Anywho, in today’s task we’ll develop a simple plugin, which will send an email to any user who hasn’t logged in for a particular number of days. This proves to be particularly useful in LMS and e-leaning plugins, but can be used for other purposes. So, after reading this post, you’ll have a code which can:

  • Set up a wp_cron, to trigger emails whenever they need to be sent
  • Create and update a new user meta, to save the last time an user has been logged in
  • When the cron is fired, a class to detect users who have been inactive for the defined period of time, and send them an email alert

The plugin main file

In the plugin main file, as usual, we don’t want to have tonnes of functions or classes. Opposingly, we’d prefer to keep just the necessary and requiring the classes in separate. Although I usually do that using Composer, we can simply create the classes and require all of them in the main file.

So let’s begin. The main file, besides all plugin meta, needs to set up your new scheduled task, or wp_cron, in which the email sender will be hooked. Also, you can add constants if you prefer. So let’s do that:

// After plugin meta, constants, etc...
register_activation_hook( __FILE__, 'plugin_notifications_activate');
register_deactivation_hook( __FILE__, 'plugin_notifications_deactivate');

function plugin_notifications_activate() {
	if ( ! wp_next_scheduled( 'plugin_notifications_cron' ) ) {
		wp_schedule_event( time(), 'twicedaily', 'plugin_notifications_cron' );

function plugin_notifications_deactivate() {
	wp_unschedule_hook( 'plugin_notifications_cron' );

Explaining: we use the activation hook for defining the new schedule task, but also add a deactivation hook – if our plugin is deactivated, the schedule task becomes useless, so we remove it.

Now we have the main file, let’s create three different classes: Init.php, Mail.php and User.php. Each of these will manage a particular aspect of the plugin. Of course we could pack those processes altogether, but this way looks nicer and more organized. Then, still in the main file, let’s require all classes (in the example, let’s consider all files to be in the plugin’s root path.

require 'Init.php';
require 'User.php';
require 'Mail.php';

$init = new Init(); // Once all classes are done, this will start the plugin.

The class Init()

This one is the easiest – its only function is to control and instance the other classes in the plugin. This makes your life easier if you decide to extend or include new features in this plugin, such as a settings page. Try to keep the logic (main file) >> (Init class) >> (Other classes and files).

class Init
	protected $user;
	protected $emails;

	public function __construct()

		$this->user = new User();
		$this->emails = new Mail();	

The class User()

This one will be also simple. In this plugin, we just want a new usermeta, so we can track login times. Alternatively, we could track the logout times – and this would be possible just by replacing the action we are using in this class.

class User
	public function __construct()
		add_action('wp_login', array($this, 'plugin_user_login'));

	public function plugin_user_login($user_login, $user)
		if(!current_user_can('administrator')) {
			update_user_meta($user->ID, 'plugin_last_login', time());

Explaining, that means every time an user logs in, the usermeta ‘plugin_last_login’ will be updated or added if it doesn’t exist, being the current time the updated value. Still, if the user is an administrator, no meta will be saved.

The class Mail()

This one will do most of the work. It will get the usermeta, to find whether each user must be noticed or not. For users that match the search, it will send an email alert. So let’s see the whole thing:

class Emails

	public function __construct()
		add_action('plugin_notifications_cron', array($this, 'get_lazy_students'));

	public function get_lazy_students()
		$users = new \WP_User_Query([
		    'meta_key'     => 'plugin_last_login',
		    'meta_value'   => strtotime( '-3 days' ), // The "X" days
		    'meta_compare' => '<',

		foreach( $users->get_results() as $user ) {
		      	__( 'The Title of the E-mail'),
		      	__( 'The message of the e-mail.')

So, explaining this last: as you probably noticed, the hook being used in this class is the name of the scheduled task we defined in the plugin’s main file. As our scheduled has been defined to fire twice a day, this means each 12 hours, this classes wil be performing an user query, in order to find any user who hasn’t logged in for the last 3 days.

If 10 users haven’t done that, the same function will be sending them a notice email. Developing further, those 3 days could easily be a variable, as well as the email title or its message. Also, the message can be sent in HTML, even though that would ask for a particular HTTP header.

Anyway, this small plugin will be sending notices to inactive users, and can be extended in many ways: adding variables, user roles, being associated to a custom post type to edit the message and the title of the emails using the backend.