<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[BuddyPress][8560] trunk/src/bp-settings: When a user changes her email address, require email verification of the new address</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://buddypress.trac.wordpress.org/changeset/8560">8560</a></dd>
<dt>Author</dt> <dd>boonebgorges</dd>
<dt>Date</dt> <dd>2014-07-05 19:01:09 +0000 (Sat, 05 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>When a user changes her email address, require email verification of the new address

This feature, built into WordPress MS by default (when updating one's profile
via the Dashboard), ensures that new email addresses are valid and not
mistyped, helping to avoid unintentionally locked-out accounts.

Fixes <a href="http://buddypress.trac.wordpress.org/ticket/2265">#2265</a>

Props j.conti for an initial patch</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcbpsettingsbpsettingsactionsphp">trunk/src/bp-settings/bp-settings-actions.php</a></li>
<li><a href="#trunksrcbpsettingsbpsettingstemplatephp">trunk/src/bp-settings/bp-settings-template.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcbpsettingsbpsettingsactionsphp"></a>
<div class="modfile"><h4>Modified: trunk/src/bp-settings/bp-settings-actions.php (8559 => 8560)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/bp-settings/bp-settings-actions.php    2014-07-05 12:24:20 UTC (rev 8559)
+++ trunk/src/bp-settings/bp-settings-actions.php       2014-07-05 19:01:09 UTC (rev 8560)
</span><span class="lines">@@ -65,11 +65,13 @@
</span><span class="cx"> 
</span><span class="cx">          if ( !empty( $_POST['email'] ) ) {
</span><span class="cx"> 
</span><del>-                       // What is missing from the profile page vs signup - lets double check the goodies
-                       $user_email = sanitize_email( esc_html( trim( $_POST['email'] ) ) );
</del><ins>+                        // What is missing from the profile page vs signup -
+                       // let's double check the goodies
+                       $user_email     = sanitize_email( esc_html( trim( $_POST['email'] ) ) );
+                       $old_user_email = $bp->displayed_user->userdata->user_email;
</ins><span class="cx"> 
</span><span class="cx">                  // User is changing email address
</span><del>-                       if ( $bp->displayed_user->userdata->user_email != $user_email ) {
</del><ins>+                        if ( $old_user_email != $user_email ) {
</ins><span class="cx"> 
</span><span class="cx">                          // Run some tests on the email address
</span><span class="cx">                          $email_checks = bp_core_validate_email_address( $user_email );
</span><span class="lines">@@ -88,9 +90,59 @@
</span><span class="cx">                                  }
</span><span class="cx">                          }
</span><span class="cx"> 
</span><del>-                               // Yay we made it!
</del><ins>+                                // Store a hash to enable email validation
</ins><span class="cx">                           if ( false === $email_error ) {
</span><del>-                                       $update_user->user_email = $user_email;
</del><ins>+                                        $hash = wp_hash( $_POST['email'] );
+
+                                       $pending_email = array(
+                                               'hash'     => $hash,
+                                               'newemail' => $user_email,
+                                       );
+
+                                       bp_update_user_meta( bp_displayed_user_id(), 'pending_email_change', $pending_email );
+
+                                       $email_text = sprintf(
+                                               __( 'Dear %1$s,
+
+You recently changed the email address associated with your account on %2$s.
+If this is correct, please click on the following link to complete the change:
+%3$s
+
+You can safely ignore and delete this email if you do not want to take this action or if you have received this email in error.
+
+This email has been sent to %4$s.
+
+Regards,
+%5$s
+%6$s', 'buddypress' ),
+                                               bp_core_get_user_displayname( bp_displayed_user_id() ),
+                                               bp_get_site_name(),
+                                               esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/?verify_email_change=' . $hash ),
+                                               $user_email,
+                                               bp_get_site_name(),
+                                               bp_get_root_domain()
+                                       );
+
+                                       /**
+                                        * Filter the email text sent when a user changes emails.
+                                        *
+                                        * @since BuddyPress (2.1.0)
+                                        *
+                                        * @param string $email_text Text of the email.
+                                        * @param string $new_user_email New user email that
+                                        *        the current user has changed to.
+                                        * @param string $old_user_email Existing email addres
+                                        *        for the current user.
+                                        * @param object $update_user Userdata for the current user.
+                                        */
+                                       $content = apply_filters( 'bp_new_user_email_content', $email_text, $user_email, $old_user_email, $update_user );
+
+                                       // Send the verification email
+                                       wp_mail( $user_email, sprintf( __( '[%s] Verify your new email address', 'buddypress' ), wp_specialchars_decode( bp_get_site_name() ) ), $content );
+
+                                       // We mark that the change has taken place so as to ensure a
+                                       // success message, even though verification is still required
+                                       $_POST['email'] = $current_user->user_email;
</ins><span class="cx">                                   $email_changed = true;
</span><span class="cx">                          }
</span><span class="cx"> 
</span><span class="lines">@@ -355,3 +407,58 @@
</span><span class="cx">  }
</span><span class="cx"> }
</span><span class="cx"> add_action( 'bp_actions', 'bp_settings_action_delete_account' );
</span><ins>+
+/**
+ * Process email change verification or cancel requests.
+ *
+ * @since BuddyPress (2.1.0)
+ */
+function bp_settings_verify_email_change(){
+       if ( ! bp_is_settings_component() ) {
+               return;
+       }
+
+       if ( ! bp_is_my_profile() ) {
+               return;
+       }
+
+       $redirect_to = trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() );
+
+       // Email change is being verified
+       if ( isset( $_GET['verify_email_change'] ) ) {
+               $pending_email = bp_get_user_meta( bp_displayed_user_id(), 'pending_email_change' );
+
+               // Bail if the hash provided doesn't match the one saved in the database
+               if ( urldecode( $_GET['verify_email_change'] ) !== $pending_email['hash'] ) {
+                       return;
+               }
+
+               $email_changed = wp_update_user( array(
+                       'ID'         => bp_displayed_user_id(),
+                       'user_email' => trim( $pending_email['newemail'] ),
+               ) );
+
+               if ( $email_changed ) {
+                       // Delete the pending email change key
+                       bp_delete_user_meta( bp_displayed_user_id(), 'pending_email_change' );
+
+                       // Post a success message and redirect
+                       bp_core_add_message( __( 'You have successfully verified your new email address.', 'buddypress' ) );
+               } else {
+                       // Unknown error
+                       bp_core_add_message( __( 'There was a problem verifying your new email address. Please try again.', 'buddypress' ), 'error' );
+               }
+
+               bp_core_redirect( $redirect_to );
+               die();
+
+       // Email change is being dismissed
+       } elseif ( ! empty( $_GET['dismiss_email_change'] ) ) {
+               bp_delete_user_meta( bp_displayed_user_id(), 'pending_email_change' );
+               bp_core_add_message( __( 'You have successfully dismissed your pending email change.', 'buddypress' ) );
+
+               bp_core_redirect( $redirect_to );
+               die();
+       }
+}
+add_action( 'bp_actions', 'bp_settings_verify_email_change' );
</ins></span></pre></div>
<a id="trunksrcbpsettingsbpsettingstemplatephp"></a>
<div class="modfile"><h4>Modified: trunk/src/bp-settings/bp-settings-template.php (8559 => 8560)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/bp-settings/bp-settings-template.php   2014-07-05 12:24:20 UTC (rev 8559)
+++ trunk/src/bp-settings/bp-settings-template.php      2014-07-05 19:01:09 UTC (rev 8560)
</span><span class="lines">@@ -55,3 +55,29 @@
</span><span class="cx">  function bp_get_settings_root_slug() {
</span><span class="cx">          return apply_filters( 'bp_get_settings_root_slug', buddypress()->settings->root_slug );
</span><span class="cx">  }
</span><ins>+
+/**
+ * Add the 'pending email change' message to the settings page.
+ *
+ * @since BuddyPress (2.1.0)
+ */
+function bp_settings_pending_email_notice() {
+       $pending_email = bp_get_user_meta( bp_displayed_user_id(), 'pending_email_change', true );
+
+       if ( empty( $pending_email['newemail'] ) ) {
+               return;
+       }
+
+       if ( bp_get_displayed_user_email() == $pending_email['newemail'] ) {
+               return;
+       }
+
+       ?>
+
+       <div id="message" class="bp-template-notice error">
+               <p><?php printf( __( 'There is a pending change of your email address to <code>%1$s</code>.<br />Check your email (<code>%2$s</code>) for the verification link. <a href="%3$s">Cancel</a>', 'buddypress' ), $pending_email['newemail'], bp_get_displayed_user_email(), esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/?dismiss_email_change=1' ) ) ?></p>
+       </div>
+
+       <?php
+}
+add_action( 'bp_before_member_settings_template', 'bp_settings_pending_email_notice' );
</ins></span></pre>
</div>
</div>

</body>
</html>