Jump to content
Torsten Baldes

Send email with changes when user profile is changed

Recommended Posts


I'm building a site with user profiles, where the users can change and update their profile.

For different reasons it's important that the person who oversees these users get's an email, when a user updates his profile. At best with all the values that changed and their value before. 

I tried to hook into User::changed and this kind of works, but it get's triggered for every field, that's changed. With each trigger the list of fields also get's longer, so that only the last run contains all the changed fields.

This would mean, i would send multiple emails for one profile change. Is there a way to prevent this and get all changes at once in only one hook run?

This is my code so far (in ready.php):

wire('user')->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues);

wire()->addHookAfter("User::changed", null, function($event){
	$user = $event->object;
	$changes = $user->getChanges(true);

	// output changes as log entry
	wire('log')->save('testchangelog', print_r($changes, true) );

	// TODO: send mail



Share this post

Link to post
Share on other sites

Hi @Torsten Baldes,

I am also not really a pro, but maybe it can help nevertheless.  Did you already try to hook after Pages::saved and filter to only run for user template?

This way the hook runs only if the user page is saved and you can get all changed fields. 

  • Like 1

Share this post

Link to post
Share on other sites

Hi @Torsten Baldes, you could try the following:

wire('user')->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues);

wire()->addHookAfter('Pages::save', function($event) {  // >>> ON PAGE SAVE
	$page = $event->arguments(0);

	if($page->template->name === 'user') { // >>> APPLY ONLY TO USER TEMPLATE
      $changes = user()->getChanges(true);

      // output changes as log entry
      wire('log')->save('testchangelog', print_r($changes, true) );

      $m = new WireMail();
      $m->from('Your email From');
      $m->to('Your email To');
      $m->subject('Your email subject');
      $m->body('Your email text');


Note: made a couple of corrections and changed to WireMail as per @horst suggestion. Still testing if changes are recorded...

  • Like 2

Share this post

Link to post
Share on other sites
1 hour ago, Edison said:

@mail($receipt, $subject, $body, "From:{$sender}");

Hi @Edison, if this shows the old and the new values inlog and mail, this is really good! (Will test this later when back in buero).

Only thing that should be changed is the use of (PHP) @mail function. Instead you should use wireMail(). :)

  • Like 1

Share this post

Link to post
Share on other sites

Thanks for your help!

For now I ended up with something like this:

wire('user')->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues);

wire()->addHookAfter("Pages::saved", null, function($event){
	$user = $event->arguments(0);

	if($user->template->name == 'user'){

		$userfields = $user->template->fieldgroup;
		$excludeFields = ['pass', 'roles', 'language', 'admin_theme', 'schedulerSkip', 'cpf_added'];
		$changes = $event->arguments(1);

		// check if there are any changes, if it's not an InputfieldFileAjax (also triggers the hook), the user changed his own profile, if the changed user is not a superuser (could be any other role to exclude)
		if(count($changes) && !wire('input')->get->InputfieldFileAjax && wire('user')->id == $user->id && !$user->hasRole('superuser')){

			$userfieldsArray = array();
			foreach($userfields as $userfield){
				$userfieldsArray[] = $userfield->name;

			//remove unwanted fields
			$changes = array_diff($changes, $excludeFields);

			// order changed fields like template
			$changesSorted = array();
			foreach ($userfieldsArray as $item) {
				if(in_array($item, $changes)){
					$changesSorted[] = $changes[$item];
			$changes = $changesSorted;
			unset($changesSorted); // probably not necessary
			// get the changes in a string
			$changedFields = '';
			foreach($changes as $change){
				$changedFields .= $userfields->get($change)->label . "\r\n";
			// compose the mail
			$subject = "Änderung im Nutzerprofil von  »".$user->u_fullname."«";

			$message =  "Hallo,\r\n\r\n das Nutzerprofil von ".$user->u_fullname." wurde aktualisiert.\r\nFolgende Felder haben sich geändert:\r\n\r\n" ;
			$message .= $changedFields;
			$message .= "\r\n\r\n" ;
			$message .= "Klicken Sie hier, um das Profil zu bearbeiten: ".trim(wire('urls')->httpRoot, '/').$user->editUrl ;
			$message .= "\r\n\r\n\r\n";

			$mailmessage = wire('mail')->new();
			$sent = $mailmessage->send();


I decided that it's not necessary to send the before and after values within the email. This could even be a privacy and/or security issue.

Thanks again for your ideas and help!

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...