wp/wp-includes/pluggable.php
changeset 16 a86126ab1dd4
parent 13 d255fe9cd479
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    15 	 * Some WordPress functionality is based on the current user and not based on
    15 	 * Some WordPress functionality is based on the current user and not based on
    16 	 * the signed in user. Therefore, it opens the ability to edit and perform
    16 	 * the signed in user. Therefore, it opens the ability to edit and perform
    17 	 * actions on users who aren't signed in.
    17 	 * actions on users who aren't signed in.
    18 	 *
    18 	 *
    19 	 * @since 2.0.3
    19 	 * @since 2.0.3
       
    20 	 *
    20 	 * @global WP_User $current_user The current user object which holds the user data.
    21 	 * @global WP_User $current_user The current user object which holds the user data.
    21 	 *
    22 	 *
    22 	 * @param int    $id   User ID
    23 	 * @param int    $id   User ID
    23 	 * @param string $name User's username
    24 	 * @param string $name User's username
    24 	 * @return WP_User Current user User object
    25 	 * @return WP_User Current user User object
   141 	}
   142 	}
   142 endif;
   143 endif;
   143 
   144 
   144 if ( ! function_exists( 'wp_mail' ) ) :
   145 if ( ! function_exists( 'wp_mail' ) ) :
   145 	/**
   146 	/**
   146 	 * Send mail, similar to PHP's mail
   147 	 * Sends an email, similar to PHP's mail function.
   147 	 *
   148 	 *
   148 	 * A true return value does not automatically mean that the user received the
   149 	 * A true return value does not automatically mean that the user received the
   149 	 * email successfully. It just only means that the method used was able to
   150 	 * email successfully. It just only means that the method used was able to
   150 	 * process the request without any errors.
   151 	 * process the request without any errors.
   151 	 *
   152 	 *
   152 	 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
   153 	 * The default content type is `text/plain` which does not allow using HTML.
   153 	 * creating a from address like 'Name <email@address.com>' when both are set. If
       
   154 	 * just 'wp_mail_from' is set, then just the email address will be used with no
       
   155 	 * name.
       
   156 	 *
       
   157 	 * The default content type is 'text/plain' which does not allow using HTML.
       
   158 	 * However, you can set the content type of the email by using the
   154 	 * However, you can set the content type of the email by using the
   159 	 * {@see 'wp_mail_content_type'} filter.
   155 	 * {@see 'wp_mail_content_type'} filter.
   160 	 *
   156 	 *
   161 	 * The default charset is based on the charset used on the blog. The charset can
   157 	 * The default charset is based on the charset used on the blog. The charset can
   162 	 * be set using the {@see 'wp_mail_charset'} filter.
   158 	 * be set using the {@see 'wp_mail_charset'} filter.
   163 	 *
   159 	 *
   164 	 * @since 1.2.1
   160 	 * @since 1.2.1
   165 	 *
   161 	 *
   166 	 * @global PHPMailer $phpmailer
   162 	 * @global PHPMailer\PHPMailer\PHPMailer $phpmailer
   167 	 *
   163 	 *
   168 	 * @param string|array $to          Array or comma-separated list of email addresses to send message.
   164 	 * @param string|array $to          Array or comma-separated list of email addresses to send message.
   169 	 * @param string       $subject     Email subject
   165 	 * @param string       $subject     Email subject
   170 	 * @param string       $message     Message contents
   166 	 * @param string       $message     Message contents
   171 	 * @param string|array $headers     Optional. Additional headers.
   167 	 * @param string|array $headers     Optional. Additional headers.
   172 	 * @param string|array $attachments Optional. Files to attach.
   168 	 * @param string|array $attachments Optional. Files to attach.
   173 	 * @return bool Whether the email contents were sent successfully.
   169 	 * @return bool Whether the email contents were sent successfully.
   174 	 */
   170 	 */
   175 	function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
   171 	function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
   176 		// Compact the input, apply the filters, and extract them back out
   172 		// Compact the input, apply the filters, and extract them back out.
   177 
   173 
   178 		/**
   174 		/**
   179 		 * Filters the wp_mail() arguments.
   175 		 * Filters the wp_mail() arguments.
   180 		 *
   176 		 *
   181 		 * @since 2.2.0
   177 		 * @since 2.2.0
   212 		if ( ! is_array( $attachments ) ) {
   208 		if ( ! is_array( $attachments ) ) {
   213 			$attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
   209 			$attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
   214 		}
   210 		}
   215 		global $phpmailer;
   211 		global $phpmailer;
   216 
   212 
   217 		// (Re)create it, if it's gone missing
   213 		// (Re)create it, if it's gone missing.
   218 		if ( ! ( $phpmailer instanceof PHPMailer ) ) {
   214 		if ( ! ( $phpmailer instanceof PHPMailer\PHPMailer\PHPMailer ) ) {
   219 			require_once ABSPATH . WPINC . '/class-phpmailer.php';
   215 			require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
   220 			require_once ABSPATH . WPINC . '/class-smtp.php';
   216 			require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
   221 			$phpmailer = new PHPMailer( true );
   217 			require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
   222 		}
   218 			$phpmailer = new PHPMailer\PHPMailer\PHPMailer( true );
   223 
   219 
   224 		// Headers
   220 			$phpmailer::$validator = static function ( $email ) {
   225 		$cc = $bcc = $reply_to = array();
   221 				return (bool) is_email( $email );
       
   222 			};
       
   223 		}
       
   224 
       
   225 		// Headers.
       
   226 		$cc       = array();
       
   227 		$bcc      = array();
       
   228 		$reply_to = array();
   226 
   229 
   227 		if ( empty( $headers ) ) {
   230 		if ( empty( $headers ) ) {
   228 			$headers = array();
   231 			$headers = array();
   229 		} else {
   232 		} else {
   230 			if ( ! is_array( $headers ) ) {
   233 			if ( ! is_array( $headers ) ) {
   231 				// Explode the headers out, so this function can take both
   234 				// Explode the headers out, so this function can take
   232 				// string headers and an array of headers.
   235 				// both string headers and an array of headers.
   233 				$tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
   236 				$tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
   234 			} else {
   237 			} else {
   235 				$tempheaders = $headers;
   238 				$tempheaders = $headers;
   236 			}
   239 			}
   237 			$headers = array();
   240 			$headers = array();
   238 
   241 
   239 			// If it's actually got contents
   242 			// If it's actually got contents.
   240 			if ( ! empty( $tempheaders ) ) {
   243 			if ( ! empty( $tempheaders ) ) {
   241 				// Iterate through the raw headers
   244 				// Iterate through the raw headers.
   242 				foreach ( (array) $tempheaders as $header ) {
   245 				foreach ( (array) $tempheaders as $header ) {
   243 					if ( strpos( $header, ':' ) === false ) {
   246 					if ( strpos( $header, ':' ) === false ) {
   244 						if ( false !== stripos( $header, 'boundary=' ) ) {
   247 						if ( false !== stripos( $header, 'boundary=' ) ) {
   245 							$parts    = preg_split( '/boundary=/i', trim( $header ) );
   248 							$parts    = preg_split( '/boundary=/i', trim( $header ) );
   246 							$boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
   249 							$boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
   247 						}
   250 						}
   248 						continue;
   251 						continue;
   249 					}
   252 					}
   250 					// Explode them out
   253 					// Explode them out.
   251 					list( $name, $content ) = explode( ':', trim( $header ), 2 );
   254 					list( $name, $content ) = explode( ':', trim( $header ), 2 );
   252 
   255 
   253 					// Cleanup crew
   256 					// Cleanup crew.
   254 					$name    = trim( $name );
   257 					$name    = trim( $name );
   255 					$content = trim( $content );
   258 					$content = trim( $content );
   256 
   259 
   257 					switch ( strtolower( $name ) ) {
   260 					switch ( strtolower( $name ) ) {
   258 						// Mainly for legacy -- process a From: header if it's there
   261 						// Mainly for legacy -- process a "From:" header if it's there.
   259 						case 'from':
   262 						case 'from':
   260 							$bracket_pos = strpos( $content, '<' );
   263 							$bracket_pos = strpos( $content, '<' );
   261 							if ( $bracket_pos !== false ) {
   264 							if ( false !== $bracket_pos ) {
   262 								// Text before the bracketed email is the "From" name.
   265 								// Text before the bracketed email is the "From" name.
   263 								if ( $bracket_pos > 0 ) {
   266 								if ( $bracket_pos > 0 ) {
   264 									$from_name = substr( $content, 0, $bracket_pos - 1 );
   267 									$from_name = substr( $content, 0, $bracket_pos - 1 );
   265 									$from_name = str_replace( '"', '', $from_name );
   268 									$from_name = str_replace( '"', '', $from_name );
   266 									$from_name = trim( $from_name );
   269 									$from_name = trim( $from_name );
   299 							break;
   302 							break;
   300 						case 'reply-to':
   303 						case 'reply-to':
   301 							$reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
   304 							$reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
   302 							break;
   305 							break;
   303 						default:
   306 						default:
   304 							// Add it to our grand headers array
   307 							// Add it to our grand headers array.
   305 							$headers[ trim( $name ) ] = trim( $content );
   308 							$headers[ trim( $name ) ] = trim( $content );
   306 							break;
   309 							break;
   307 					}
   310 					}
   308 				}
   311 				}
   309 			}
   312 			}
   310 		}
   313 		}
   311 
   314 
   312 		// Empty out the values that may be set
   315 		// Empty out the values that may be set.
   313 		$phpmailer->clearAllRecipients();
   316 		$phpmailer->clearAllRecipients();
   314 		$phpmailer->clearAttachments();
   317 		$phpmailer->clearAttachments();
   315 		$phpmailer->clearCustomHeaders();
   318 		$phpmailer->clearCustomHeaders();
   316 		$phpmailer->clearReplyTos();
   319 		$phpmailer->clearReplyTos();
   317 
   320 
   318 		// From email and name
   321 		// Set "From" name and email.
   319 		// If we don't have a name from the input headers
   322 
       
   323 		// If we don't have a name from the input headers.
   320 		if ( ! isset( $from_name ) ) {
   324 		if ( ! isset( $from_name ) ) {
   321 			$from_name = 'WordPress';
   325 			$from_name = 'WordPress';
   322 		}
   326 		}
   323 
   327 
   324 		/* If we don't have an email from the input headers default to wordpress@$sitename
   328 		/*
   325 		 * Some hosts will block outgoing mail from this address if it doesn't exist but
   329 		 * If we don't have an email from the input headers, default to wordpress@$sitename
   326 		 * there's no easy alternative. Defaulting to admin_email might appear to be another
   330 		 * Some hosts will block outgoing mail from this address if it doesn't exist,
   327 		 * option but some hosts may refuse to relay mail from an unknown domain. See
   331 		 * but there's no easy alternative. Defaulting to admin_email might appear to be
   328 		 * https://core.trac.wordpress.org/ticket/5007.
   332 		 * another option, but some hosts may refuse to relay mail from an unknown domain.
   329 		 */
   333 		 * See https://core.trac.wordpress.org/ticket/5007.
   330 
   334 		 */
   331 		if ( ! isset( $from_email ) ) {
   335 		if ( ! isset( $from_email ) ) {
   332 			// Get the site domain and get rid of www.
   336 			// Get the site domain and get rid of www.
   333 			$sitename = strtolower( $_SERVER['SERVER_NAME'] );
   337 			$sitename = wp_parse_url( network_home_url(), PHP_URL_HOST );
   334 			if ( substr( $sitename, 0, 4 ) == 'www.' ) {
   338 			if ( 'www.' === substr( $sitename, 0, 4 ) ) {
   335 				$sitename = substr( $sitename, 4 );
   339 				$sitename = substr( $sitename, 4 );
   336 			}
   340 			}
   337 
   341 
   338 			$from_email = 'wordpress@' . $sitename;
   342 			$from_email = 'wordpress@' . $sitename;
   339 		}
   343 		}
   356 		 */
   360 		 */
   357 		$from_name = apply_filters( 'wp_mail_from_name', $from_name );
   361 		$from_name = apply_filters( 'wp_mail_from_name', $from_name );
   358 
   362 
   359 		try {
   363 		try {
   360 			$phpmailer->setFrom( $from_email, $from_name, false );
   364 			$phpmailer->setFrom( $from_email, $from_name, false );
   361 		} catch ( phpmailerException $e ) {
   365 		} catch ( PHPMailer\PHPMailer\Exception $e ) {
   362 			$mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
   366 			$mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
   363 			$mail_error_data['phpmailer_exception_code'] = $e->getCode();
   367 			$mail_error_data['phpmailer_exception_code'] = $e->getCode();
   364 
   368 
   365 			/** This filter is documented in wp-includes/pluggable.php */
   369 			/** This filter is documented in wp-includes/pluggable.php */
   366 			do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
   370 			do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
   367 
   371 
   368 			return false;
   372 			return false;
   369 		}
   373 		}
   370 
   374 
   371 		// Set mail's subject and body
   375 		// Set mail's subject and body.
   372 		$phpmailer->Subject = $subject;
   376 		$phpmailer->Subject = $subject;
   373 		$phpmailer->Body    = $message;
   377 		$phpmailer->Body    = $message;
   374 
   378 
   375 		// Set destination addresses, using appropriate methods for handling addresses
   379 		// Set destination addresses, using appropriate methods for handling addresses.
   376 		$address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
   380 		$address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
   377 
   381 
   378 		foreach ( $address_headers as $address_header => $addresses ) {
   382 		foreach ( $address_headers as $address_header => $addresses ) {
   379 			if ( empty( $addresses ) ) {
   383 			if ( empty( $addresses ) ) {
   380 				continue;
   384 				continue;
   381 			}
   385 			}
   382 
   386 
   383 			foreach ( (array) $addresses as $address ) {
   387 			foreach ( (array) $addresses as $address ) {
   384 				try {
   388 				try {
   385 					// Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
   389 					// Break $recipient into name and address parts if in the format "Foo <bar@baz.com>".
   386 					$recipient_name = '';
   390 					$recipient_name = '';
   387 
   391 
   388 					if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
   392 					if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
   389 						if ( count( $matches ) == 3 ) {
   393 						if ( count( $matches ) == 3 ) {
   390 							$recipient_name = $matches[1];
   394 							$recipient_name = $matches[1];
   404 							break;
   408 							break;
   405 						case 'reply_to':
   409 						case 'reply_to':
   406 							$phpmailer->addReplyTo( $address, $recipient_name );
   410 							$phpmailer->addReplyTo( $address, $recipient_name );
   407 							break;
   411 							break;
   408 					}
   412 					}
   409 				} catch ( phpmailerException $e ) {
   413 				} catch ( PHPMailer\PHPMailer\Exception $e ) {
   410 					continue;
   414 					continue;
   411 				}
   415 				}
   412 			}
   416 			}
   413 		}
   417 		}
   414 
   418 
   415 		// Set to use PHP's mail()
   419 		// Set to use PHP's mail().
   416 		$phpmailer->isMail();
   420 		$phpmailer->isMail();
   417 
   421 
   418 		// Set Content-Type and charset
   422 		// Set Content-Type and charset.
   419 		// If we don't have a content-type from the input headers
   423 
       
   424 		// If we don't have a content-type from the input headers.
   420 		if ( ! isset( $content_type ) ) {
   425 		if ( ! isset( $content_type ) ) {
   421 			$content_type = 'text/plain';
   426 			$content_type = 'text/plain';
   422 		}
   427 		}
   423 
   428 
   424 		/**
   429 		/**
   430 		 */
   435 		 */
   431 		$content_type = apply_filters( 'wp_mail_content_type', $content_type );
   436 		$content_type = apply_filters( 'wp_mail_content_type', $content_type );
   432 
   437 
   433 		$phpmailer->ContentType = $content_type;
   438 		$phpmailer->ContentType = $content_type;
   434 
   439 
   435 		// Set whether it's plaintext, depending on $content_type
   440 		// Set whether it's plaintext, depending on $content_type.
   436 		if ( 'text/html' == $content_type ) {
   441 		if ( 'text/html' === $content_type ) {
   437 			$phpmailer->isHTML( true );
   442 			$phpmailer->isHTML( true );
   438 		}
   443 		}
   439 
   444 
   440 		// If we don't have a charset from the input headers
   445 		// If we don't have a charset from the input headers.
   441 		if ( ! isset( $charset ) ) {
   446 		if ( ! isset( $charset ) ) {
   442 			$charset = get_bloginfo( 'charset' );
   447 			$charset = get_bloginfo( 'charset' );
   443 		}
   448 		}
   444 
   449 
   445 		// Set the content-type and charset
       
   446 
       
   447 		/**
   450 		/**
   448 		 * Filters the default wp_mail() charset.
   451 		 * Filters the default wp_mail() charset.
   449 		 *
   452 		 *
   450 		 * @since 2.3.0
   453 		 * @since 2.3.0
   451 		 *
   454 		 *
   452 		 * @param string $charset Default email charset.
   455 		 * @param string $charset Default email charset.
   453 		 */
   456 		 */
   454 		$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
   457 		$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
   455 
   458 
   456 		// Set custom headers
   459 		// Set custom headers.
   457 		if ( ! empty( $headers ) ) {
   460 		if ( ! empty( $headers ) ) {
   458 			foreach ( (array) $headers as $name => $content ) {
   461 			foreach ( (array) $headers as $name => $content ) {
   459 				$phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
   462 				// Only add custom headers not added automatically by PHPMailer.
       
   463 				if ( ! in_array( $name, array( 'MIME-Version', 'X-Mailer' ), true ) ) {
       
   464 					try {
       
   465 						$phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
       
   466 					} catch ( PHPMailer\PHPMailer\Exception $e ) {
       
   467 						continue;
       
   468 					}
       
   469 				}
   460 			}
   470 			}
   461 
   471 
   462 			if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ) {
   472 			if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ) {
   463 				$phpmailer->addCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
   473 				$phpmailer->addCustomHeader( sprintf( 'Content-Type: %s; boundary="%s"', $content_type, $boundary ) );
   464 			}
   474 			}
   465 		}
   475 		}
   466 
   476 
   467 		if ( ! empty( $attachments ) ) {
   477 		if ( ! empty( $attachments ) ) {
   468 			foreach ( $attachments as $attachment ) {
   478 			foreach ( $attachments as $attachment ) {
   469 				try {
   479 				try {
   470 					$phpmailer->addAttachment( $attachment );
   480 					$phpmailer->addAttachment( $attachment );
   471 				} catch ( phpmailerException $e ) {
   481 				} catch ( PHPMailer\PHPMailer\Exception $e ) {
   472 					continue;
   482 					continue;
   473 				}
   483 				}
   474 			}
   484 			}
   475 		}
   485 		}
   476 
   486 
   484 		do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
   494 		do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
   485 
   495 
   486 		// Send!
   496 		// Send!
   487 		try {
   497 		try {
   488 			return $phpmailer->send();
   498 			return $phpmailer->send();
   489 		} catch ( phpmailerException $e ) {
   499 		} catch ( PHPMailer\PHPMailer\Exception $e ) {
   490 
   500 
   491 			$mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
   501 			$mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
   492 			$mail_error_data['phpmailer_exception_code'] = $e->getCode();
   502 			$mail_error_data['phpmailer_exception_code'] = $e->getCode();
   493 
   503 
   494 			/**
   504 			/**
   495 			 * Fires after a phpmailerException is caught.
   505 			 * Fires after a PHPMailer\PHPMailer\Exception is caught.
   496 			 *
   506 			 *
   497 			 * @since 4.4.0
   507 			 * @since 4.4.0
   498 			 *
   508 			 *
   499 			 * @param WP_Error $error A WP_Error object with the phpmailerException message, and an array
   509 			 * @param WP_Error $error A WP_Error object with the PHPMailer\PHPMailer\Exception message, and an array
   500 			 *                        containing the mail recipient, subject, message, headers, and attachments.
   510 			 *                        containing the mail recipient, subject, message, headers, and attachments.
   501 			 */
   511 			 */
   502 			do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
   512 			do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
   503 
   513 
   504 			return false;
   514 			return false;
   536 		 * @param string                $username Username or email address.
   546 		 * @param string                $username Username or email address.
   537 		 * @param string                $password User password
   547 		 * @param string                $password User password
   538 		 */
   548 		 */
   539 		$user = apply_filters( 'authenticate', null, $username, $password );
   549 		$user = apply_filters( 'authenticate', null, $username, $password );
   540 
   550 
   541 		if ( $user == null ) {
   551 		if ( null == $user ) {
   542 			// TODO what should the error message be? (Or would these even happen?)
   552 			// TODO: What should the error message be? (Or would these even happen?)
   543 			// Only needed if all authentication handlers fail to return anything.
   553 			// Only needed if all authentication handlers fail to return anything.
   544 			$user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Invalid username, email address or incorrect password.' ) );
   554 			$user = new WP_Error( 'authentication_failed', __( '<strong>Error</strong>: Invalid username, email address or incorrect password.' ) );
   545 		}
   555 		}
   546 
   556 
   547 		$ignore_codes = array( 'empty_username', 'empty_password' );
   557 		$ignore_codes = array( 'empty_username', 'empty_password' );
   548 
   558 
   549 		if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
   559 		if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes, true ) ) {
       
   560 			$error = $user;
       
   561 
   550 			/**
   562 			/**
   551 			 * Fires after a user login has failed.
   563 			 * Fires after a user login has failed.
   552 			 *
   564 			 *
   553 			 * @since 2.5.0
   565 			 * @since 2.5.0
   554 			 * @since 4.5.0 The value of `$username` can now be an email address.
   566 			 * @since 4.5.0 The value of `$username` can now be an email address.
   555 			 *
   567 			 * @since 5.4.0 The `$error` parameter was added.
   556 			 * @param string $username Username or email address.
   568 			 *
       
   569 			 * @param string   $username Username or email address.
       
   570 			 * @param WP_Error $error    A WP_Error object with the authentication failure details.
   557 			 */
   571 			 */
   558 			do_action( 'wp_login_failed', $username );
   572 			do_action( 'wp_login_failed', $username, $error );
   559 		}
   573 		}
   560 
   574 
   561 		return $user;
   575 		return $user;
   562 	}
   576 	}
   563 endif;
   577 endif;
   567 	 * Log the current user out.
   581 	 * Log the current user out.
   568 	 *
   582 	 *
   569 	 * @since 2.5.0
   583 	 * @since 2.5.0
   570 	 */
   584 	 */
   571 	function wp_logout() {
   585 	function wp_logout() {
       
   586 		$user_id = get_current_user_id();
       
   587 
   572 		wp_destroy_current_session();
   588 		wp_destroy_current_session();
   573 		wp_clear_auth_cookie();
   589 		wp_clear_auth_cookie();
   574 
   590 		wp_set_current_user( 0 );
   575 		/**
   591 
   576 		 * Fires after a user is logged-out.
   592 		/**
       
   593 		 * Fires after a user is logged out.
   577 		 *
   594 		 *
   578 		 * @since 1.5.0
   595 		 * @since 1.5.0
   579 		 */
   596 		 * @since 5.5.0 Added the `$user_id` parameter.
   580 		do_action( 'wp_logout' );
   597 		 *
       
   598 		 * @param int $user_id ID of the user that was logged out.
       
   599 		 */
       
   600 		do_action( 'wp_logout', $user_id );
   581 	}
   601 	}
   582 endif;
   602 endif;
   583 
   603 
   584 if ( ! function_exists( 'wp_validate_auth_cookie' ) ) :
   604 if ( ! function_exists( 'wp_validate_auth_cookie' ) ) :
   585 	/**
   605 	/**
   593 	 *
   613 	 *
   594 	 * @since 2.5.0
   614 	 * @since 2.5.0
   595 	 *
   615 	 *
   596 	 * @global int $login_grace_period
   616 	 * @global int $login_grace_period
   597 	 *
   617 	 *
   598 	 * @param string $cookie Optional. If used, will validate contents instead of cookie's
   618 	 * @param string $cookie Optional. If used, will validate contents instead of cookie's.
   599 	 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
   619 	 * @param string $scheme Optional. The cookie scheme to use: 'auth', 'secure_auth', or 'logged_in'.
   600 	 * @return false|int False if invalid cookie, User ID if valid.
   620 	 * @return int|false User ID if valid cookie, false if invalid.
   601 	 */
   621 	 */
   602 	function wp_validate_auth_cookie( $cookie = '', $scheme = '' ) {
   622 	function wp_validate_auth_cookie( $cookie = '', $scheme = '' ) {
   603 		if ( ! $cookie_elements = wp_parse_auth_cookie( $cookie, $scheme ) ) {
   623 		$cookie_elements = wp_parse_auth_cookie( $cookie, $scheme );
       
   624 		if ( ! $cookie_elements ) {
   604 			/**
   625 			/**
   605 			 * Fires if an authentication cookie is malformed.
   626 			 * Fires if an authentication cookie is malformed.
   606 			 *
   627 			 *
   607 			 * @since 2.7.0
   628 			 * @since 2.7.0
   608 			 *
   629 			 *
   612 			 */
   633 			 */
   613 			do_action( 'auth_cookie_malformed', $cookie, $scheme );
   634 			do_action( 'auth_cookie_malformed', $cookie, $scheme );
   614 			return false;
   635 			return false;
   615 		}
   636 		}
   616 
   637 
   617 		$scheme   = $cookie_elements['scheme'];
   638 		$scheme     = $cookie_elements['scheme'];
   618 		$username = $cookie_elements['username'];
   639 		$username   = $cookie_elements['username'];
   619 		$hmac     = $cookie_elements['hmac'];
   640 		$hmac       = $cookie_elements['hmac'];
   620 		$token    = $cookie_elements['token'];
   641 		$token      = $cookie_elements['token'];
   621 		$expired  = $expiration = $cookie_elements['expiration'];
   642 		$expired    = $cookie_elements['expiration'];
   622 
   643 		$expiration = $cookie_elements['expiration'];
   623 		// Allow a grace period for POST and Ajax requests
   644 
   624 		if ( wp_doing_ajax() || 'POST' == $_SERVER['REQUEST_METHOD'] ) {
   645 		// Allow a grace period for POST and Ajax requests.
       
   646 		if ( wp_doing_ajax() || 'POST' === $_SERVER['REQUEST_METHOD'] ) {
   625 			$expired += HOUR_IN_SECONDS;
   647 			$expired += HOUR_IN_SECONDS;
   626 		}
   648 		}
   627 
   649 
   628 		// Quick check to see if an honest cookie has expired
   650 		// Quick check to see if an honest cookie has expired.
   629 		if ( $expired < time() ) {
   651 		if ( $expired < time() ) {
   630 			/**
   652 			/**
   631 			 * Fires once an authentication cookie has expired.
   653 			 * Fires once an authentication cookie has expired.
   632 			 *
   654 			 *
   633 			 * @since 2.7.0
   655 			 * @since 2.7.0
   634 			 *
   656 			 *
   635 			 * @param array $cookie_elements An array of data for the authentication cookie.
   657 			 * @param string[] $cookie_elements An array of data for the authentication cookie.
   636 			 */
   658 			 */
   637 			do_action( 'auth_cookie_expired', $cookie_elements );
   659 			do_action( 'auth_cookie_expired', $cookie_elements );
   638 			return false;
   660 			return false;
   639 		}
   661 		}
   640 
   662 
   643 			/**
   665 			/**
   644 			 * Fires if a bad username is entered in the user authentication process.
   666 			 * Fires if a bad username is entered in the user authentication process.
   645 			 *
   667 			 *
   646 			 * @since 2.7.0
   668 			 * @since 2.7.0
   647 			 *
   669 			 *
   648 			 * @param array $cookie_elements An array of data for the authentication cookie.
   670 			 * @param string[] $cookie_elements An array of data for the authentication cookie.
   649 			 */
   671 			 */
   650 			do_action( 'auth_cookie_bad_username', $cookie_elements );
   672 			do_action( 'auth_cookie_bad_username', $cookie_elements );
   651 			return false;
   673 			return false;
   652 		}
   674 		}
   653 
   675 
   663 			/**
   685 			/**
   664 			 * Fires if a bad authentication cookie hash is encountered.
   686 			 * Fires if a bad authentication cookie hash is encountered.
   665 			 *
   687 			 *
   666 			 * @since 2.7.0
   688 			 * @since 2.7.0
   667 			 *
   689 			 *
   668 			 * @param array $cookie_elements An array of data for the authentication cookie.
   690 			 * @param string[] $cookie_elements An array of data for the authentication cookie.
   669 			 */
   691 			 */
   670 			do_action( 'auth_cookie_bad_hash', $cookie_elements );
   692 			do_action( 'auth_cookie_bad_hash', $cookie_elements );
   671 			return false;
   693 			return false;
   672 		}
   694 		}
   673 
   695 
   674 		$manager = WP_Session_Tokens::get_instance( $user->ID );
   696 		$manager = WP_Session_Tokens::get_instance( $user->ID );
   675 		if ( ! $manager->verify( $token ) ) {
   697 		if ( ! $manager->verify( $token ) ) {
       
   698 			/**
       
   699 			 * Fires if a bad session token is encountered.
       
   700 			 *
       
   701 			 * @since 4.0.0
       
   702 			 *
       
   703 			 * @param string[] $cookie_elements An array of data for the authentication cookie.
       
   704 			 */
   676 			do_action( 'auth_cookie_bad_session_token', $cookie_elements );
   705 			do_action( 'auth_cookie_bad_session_token', $cookie_elements );
   677 			return false;
   706 			return false;
   678 		}
   707 		}
   679 
   708 
   680 		// Ajax/POST grace period set above
   709 		// Ajax/POST grace period set above.
   681 		if ( $expiration < time() ) {
   710 		if ( $expiration < time() ) {
   682 			$GLOBALS['login_grace_period'] = 1;
   711 			$GLOBALS['login_grace_period'] = 1;
   683 		}
   712 		}
   684 
   713 
   685 		/**
   714 		/**
   686 		 * Fires once an authentication cookie has been validated.
   715 		 * Fires once an authentication cookie has been validated.
   687 		 *
   716 		 *
   688 		 * @since 2.7.0
   717 		 * @since 2.7.0
   689 		 *
   718 		 *
   690 		 * @param array   $cookie_elements An array of data for the authentication cookie.
   719 		 * @param string[] $cookie_elements An array of data for the authentication cookie.
   691 		 * @param WP_User $user            User object.
   720 		 * @param WP_User  $user            User object.
   692 		 */
   721 		 */
   693 		do_action( 'auth_cookie_valid', $cookie_elements, $user );
   722 		do_action( 'auth_cookie_valid', $cookie_elements, $user );
   694 
   723 
   695 		return $user->ID;
   724 		return $user->ID;
   696 	}
   725 	}
   697 endif;
   726 endif;
   698 
   727 
   699 if ( ! function_exists( 'wp_generate_auth_cookie' ) ) :
   728 if ( ! function_exists( 'wp_generate_auth_cookie' ) ) :
   700 	/**
   729 	/**
   701 	 * Generate authentication cookie contents.
   730 	 * Generates authentication cookie contents.
   702 	 *
   731 	 *
   703 	 * @since 2.5.0
   732 	 * @since 2.5.0
   704 	 * @since 4.0.0 The `$token` parameter was added.
   733 	 * @since 4.0.0 The `$token` parameter was added.
   705 	 *
   734 	 *
   706 	 * @param int    $user_id    User ID
   735 	 * @param int    $user_id    User ID.
   707 	 * @param int    $expiration The time the cookie expires as a UNIX timestamp.
   736 	 * @param int    $expiration The time the cookie expires as a UNIX timestamp.
   708 	 * @param string $scheme     Optional. The cookie scheme to use: auth, secure_auth, or logged_in
   737 	 * @param string $scheme     Optional. The cookie scheme to use: 'auth', 'secure_auth', or 'logged_in'.
   709 	 * @param string $token      User's session token to use for this cookie
   738 	 *                           Default 'auth'.
       
   739 	 * @param string $token      User's session token to use for this cookie.
   710 	 * @return string Authentication cookie contents. Empty string if user does not exist.
   740 	 * @return string Authentication cookie contents. Empty string if user does not exist.
   711 	 */
   741 	 */
   712 	function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
   742 	function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
   713 		$user = get_userdata( $user_id );
   743 		$user = get_userdata( $user_id );
   714 		if ( ! $user ) {
   744 		if ( ! $user ) {
   746 	}
   776 	}
   747 endif;
   777 endif;
   748 
   778 
   749 if ( ! function_exists( 'wp_parse_auth_cookie' ) ) :
   779 if ( ! function_exists( 'wp_parse_auth_cookie' ) ) :
   750 	/**
   780 	/**
   751 	 * Parse a cookie into its components
   781 	 * Parses a cookie into its components.
   752 	 *
   782 	 *
   753 	 * @since 2.7.0
   783 	 * @since 2.7.0
   754 	 *
   784 	 *
   755 	 * @param string $cookie
   785 	 * @param string $cookie Authentication cookie.
   756 	 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
   786 	 * @param string $scheme Optional. The cookie scheme to use: 'auth', 'secure_auth', or 'logged_in'.
   757 	 * @return array|false Authentication cookie components
   787 	 * @return string[]|false Authentication cookie components.
   758 	 */
   788 	 */
   759 	function wp_parse_auth_cookie( $cookie = '', $scheme = '' ) {
   789 	function wp_parse_auth_cookie( $cookie = '', $scheme = '' ) {
   760 		if ( empty( $cookie ) ) {
   790 		if ( empty( $cookie ) ) {
   761 			switch ( $scheme ) {
   791 			switch ( $scheme ) {
   762 				case 'auth':
   792 				case 'auth':
   795 	}
   825 	}
   796 endif;
   826 endif;
   797 
   827 
   798 if ( ! function_exists( 'wp_set_auth_cookie' ) ) :
   828 if ( ! function_exists( 'wp_set_auth_cookie' ) ) :
   799 	/**
   829 	/**
   800 	 * Log in a user by setting authentication cookies.
   830 	 * Sets the authentication cookies based on user ID.
   801 	 *
   831 	 *
   802 	 * The $remember parameter increases the time that the cookie will be kept. The
   832 	 * The $remember parameter increases the time that the cookie will be kept. The
   803 	 * default the cookie is kept without remembering is two days. When $remember is
   833 	 * default the cookie is kept without remembering is two days. When $remember is
   804 	 * set, the cookies will be kept for 14 days or two weeks.
   834 	 * set, the cookies will be kept for 14 days or two weeks.
   805 	 *
   835 	 *
   806 	 * @since 2.5.0
   836 	 * @since 2.5.0
   807 	 * @since 4.3.0 Added the `$token` parameter.
   837 	 * @since 4.3.0 Added the `$token` parameter.
   808 	 *
   838 	 *
   809 	 * @param int    $user_id  User ID
   839 	 * @param int         $user_id  User ID.
   810 	 * @param bool   $remember Whether to remember the user
   840 	 * @param bool        $remember Whether to remember the user.
   811 	 * @param mixed  $secure   Whether the admin cookies should only be sent over HTTPS.
   841 	 * @param bool|string $secure   Whether the auth cookie should only be sent over HTTPS. Default is an empty
   812 	 *                         Default is_ssl().
   842 	 *                              string which means the value of `is_ssl()` will be used.
   813 	 * @param string $token    Optional. User's session token to use for this cookie.
   843 	 * @param string      $token    Optional. User's session token to use for this cookie.
   814 	 */
   844 	 */
   815 	function wp_set_auth_cookie( $user_id, $remember = false, $secure = '', $token = '' ) {
   845 	function wp_set_auth_cookie( $user_id, $remember = false, $secure = '', $token = '' ) {
   816 		if ( $remember ) {
   846 		if ( $remember ) {
   817 			/**
   847 			/**
   818 			 * Filters the duration of the authentication cookie expiration period.
   848 			 * Filters the duration of the authentication cookie expiration period.
   838 
   868 
   839 		if ( '' === $secure ) {
   869 		if ( '' === $secure ) {
   840 			$secure = is_ssl();
   870 			$secure = is_ssl();
   841 		}
   871 		}
   842 
   872 
   843 		// Front-end cookie is secure when the auth cookie is secure and the site's home URL is forced HTTPS.
   873 		// Front-end cookie is secure when the auth cookie is secure and the site's home URL uses HTTPS.
   844 		$secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
   874 		$secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
   845 
   875 
   846 		/**
   876 		/**
   847 		 * Filters whether the connection is secure.
   877 		 * Filters whether the auth cookie should only be sent over HTTPS.
   848 		 *
   878 		 *
   849 		 * @since 3.1.0
   879 		 * @since 3.1.0
   850 		 *
   880 		 *
   851 		 * @param bool $secure  Whether the connection is secure.
   881 		 * @param bool $secure  Whether the cookie should only be sent over HTTPS.
   852 		 * @param int  $user_id User ID.
   882 		 * @param int  $user_id User ID.
   853 		 */
   883 		 */
   854 		$secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
   884 		$secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
   855 
   885 
   856 		/**
   886 		/**
   857 		 * Filters whether to use a secure cookie when logged-in.
   887 		 * Filters whether the logged in cookie should only be sent over HTTPS.
   858 		 *
   888 		 *
   859 		 * @since 3.1.0
   889 		 * @since 3.1.0
   860 		 *
   890 		 *
   861 		 * @param bool $secure_logged_in_cookie Whether to use a secure cookie when logged-in.
   891 		 * @param bool $secure_logged_in_cookie Whether the logged in cookie should only be sent over HTTPS.
   862 		 * @param int  $user_id                 User ID.
   892 		 * @param int  $user_id                 User ID.
   863 		 * @param bool $secure                  Whether the connection is secure.
   893 		 * @param bool $secure                  Whether the auth cookie should only be sent over HTTPS.
   864 		 */
   894 		 */
   865 		$secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
   895 		$secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
   866 
   896 
   867 		if ( $secure ) {
   897 		if ( $secure ) {
   868 			$auth_cookie_name = SECURE_AUTH_COOKIE;
   898 			$auth_cookie_name = SECURE_AUTH_COOKIE;
   951 		/** This filter is documented in wp-includes/pluggable.php */
   981 		/** This filter is documented in wp-includes/pluggable.php */
   952 		if ( ! apply_filters( 'send_auth_cookies', true ) ) {
   982 		if ( ! apply_filters( 'send_auth_cookies', true ) ) {
   953 			return;
   983 			return;
   954 		}
   984 		}
   955 
   985 
   956 		// Auth cookies
   986 		// Auth cookies.
   957 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
   987 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
   958 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
   988 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
   959 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
   989 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
   960 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
   990 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
   961 		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   991 		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   962 		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   992 		setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   963 
   993 
   964 		// Settings cookies
   994 		// Settings cookies.
   965 		setcookie( 'wp-settings-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
   995 		setcookie( 'wp-settings-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
   966 		setcookie( 'wp-settings-time-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
   996 		setcookie( 'wp-settings-time-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
   967 
   997 
   968 		// Old cookies
   998 		// Old cookies.
   969 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   999 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   970 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
  1000 		setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   971 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
  1001 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   972 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
  1002 		setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   973 
  1003 
   974 		// Even older cookies
  1004 		// Even older cookies.
   975 		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
  1005 		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   976 		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
  1006 		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   977 		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
  1007 		setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   978 		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
  1008 		setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
   979 
  1009 
   980 		// Post password cookie
  1010 		// Post password cookie.
   981 		setcookie( 'wp-postpass_' . COOKIEHASH, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
  1011 		setcookie( 'wp-postpass_' . COOKIEHASH, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
   982 	}
  1012 	}
   983 endif;
  1013 endif;
   984 
  1014 
   985 if ( ! function_exists( 'is_user_logged_in' ) ) :
  1015 if ( ! function_exists( 'is_user_logged_in' ) ) :
  1003 
  1033 
  1004 if ( ! function_exists( 'auth_redirect' ) ) :
  1034 if ( ! function_exists( 'auth_redirect' ) ) :
  1005 	/**
  1035 	/**
  1006 	 * Checks if a user is logged in, if not it redirects them to the login page.
  1036 	 * Checks if a user is logged in, if not it redirects them to the login page.
  1007 	 *
  1037 	 *
       
  1038 	 * When this code is called from a page, it checks to see if the user viewing the page is logged in.
       
  1039 	 * If the user is not logged in, they are redirected to the login page. The user is redirected
       
  1040 	 * in such a way that, upon logging in, they will be sent directly to the page they were originally
       
  1041 	 * trying to access.
       
  1042 	 *
  1008 	 * @since 1.5.0
  1043 	 * @since 1.5.0
  1009 	 */
  1044 	 */
  1010 	function auth_redirect() {
  1045 	function auth_redirect() {
  1011 		// Checks if a user is logged in, if not redirects them to the login page
       
  1012 
       
  1013 		$secure = ( is_ssl() || force_ssl_admin() );
  1046 		$secure = ( is_ssl() || force_ssl_admin() );
  1014 
  1047 
  1015 		/**
  1048 		/**
  1016 		 * Filters whether to use a secure authentication redirect.
  1049 		 * Filters whether to use a secure authentication redirect.
  1017 		 *
  1050 		 *
  1019 		 *
  1052 		 *
  1020 		 * @param bool $secure Whether to use a secure authentication redirect. Default false.
  1053 		 * @param bool $secure Whether to use a secure authentication redirect. Default false.
  1021 		 */
  1054 		 */
  1022 		$secure = apply_filters( 'secure_auth_redirect', $secure );
  1055 		$secure = apply_filters( 'secure_auth_redirect', $secure );
  1023 
  1056 
  1024 		// If https is required and request is http, redirect
  1057 		// If https is required and request is http, redirect.
  1025 		if ( $secure && ! is_ssl() && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
  1058 		if ( $secure && ! is_ssl() && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
  1026 			if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
  1059 			if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
  1027 				wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
  1060 				wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
  1028 				exit();
  1061 				exit;
  1029 			} else {
  1062 			} else {
  1030 				wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1063 				wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1031 				exit();
  1064 				exit;
  1032 			}
  1065 			}
  1033 		}
  1066 		}
  1034 
  1067 
  1035 		/**
  1068 		/**
  1036 		 * Filters the authentication redirect scheme.
  1069 		 * Filters the authentication redirect scheme.
  1039 		 *
  1072 		 *
  1040 		 * @param string $scheme Authentication redirect scheme. Default empty.
  1073 		 * @param string $scheme Authentication redirect scheme. Default empty.
  1041 		 */
  1074 		 */
  1042 		$scheme = apply_filters( 'auth_redirect_scheme', '' );
  1075 		$scheme = apply_filters( 'auth_redirect_scheme', '' );
  1043 
  1076 
  1044 		if ( $user_id = wp_validate_auth_cookie( '', $scheme ) ) {
  1077 		$user_id = wp_validate_auth_cookie( '', $scheme );
       
  1078 		if ( $user_id ) {
  1045 			/**
  1079 			/**
  1046 			 * Fires before the authentication redirect.
  1080 			 * Fires before the authentication redirect.
  1047 			 *
  1081 			 *
  1048 			 * @since 2.8.0
  1082 			 * @since 2.8.0
  1049 			 *
  1083 			 *
  1053 
  1087 
  1054 			// If the user wants ssl but the session is not ssl, redirect.
  1088 			// If the user wants ssl but the session is not ssl, redirect.
  1055 			if ( ! $secure && get_user_option( 'use_ssl', $user_id ) && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
  1089 			if ( ! $secure && get_user_option( 'use_ssl', $user_id ) && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
  1056 				if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
  1090 				if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
  1057 					wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
  1091 					wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
  1058 					exit();
  1092 					exit;
  1059 				} else {
  1093 				} else {
  1060 					wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1094 					wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1061 					exit();
  1095 					exit;
  1062 				}
  1096 				}
  1063 			}
  1097 			}
  1064 
  1098 
  1065 			return;  // The cookie is good so we're done
  1099 			return; // The cookie is good, so we're done.
  1066 		}
  1100 		}
  1067 
  1101 
  1068 		// The cookie is no good so force login
  1102 		// The cookie is no good, so force login.
  1069 		nocache_headers();
  1103 		nocache_headers();
  1070 
  1104 
  1071 		$redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1105 		$redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
  1072 
  1106 
  1073 		$login_url = wp_login_url( $redirect, true );
  1107 		$login_url = wp_login_url( $redirect, true );
  1074 
  1108 
  1075 		wp_redirect( $login_url );
  1109 		wp_redirect( $login_url );
  1076 		exit();
  1110 		exit;
  1077 	}
  1111 	}
  1078 endif;
  1112 endif;
  1079 
  1113 
  1080 if ( ! function_exists( 'check_admin_referer' ) ) :
  1114 if ( ! function_exists( 'check_admin_referer' ) ) :
  1081 	/**
  1115 	/**
  1082 	 * Makes sure that a user was referred from another admin page.
  1116 	 * Ensures intent by verifying that a user was referred from another admin page with the correct security nonce.
  1083 	 *
  1117 	 *
  1084 	 * To avoid security exploits.
  1118 	 * This function ensures the user intends to perform a given action, which helps protect against clickjacking style
       
  1119 	 * attacks. It verifies intent, not authorisation, therefore it does not verify the user's capabilities. This should
       
  1120 	 * be performed with `current_user_can()` or similar.
       
  1121 	 *
       
  1122 	 * If the nonce value is invalid, the function will exit with an "Are You Sure?" style message.
  1085 	 *
  1123 	 *
  1086 	 * @since 1.2.0
  1124 	 * @since 1.2.0
  1087 	 *
  1125 	 * @since 2.5.0 The `$query_arg` parameter was added.
  1088 	 * @param int|string $action    Action nonce.
  1126 	 *
  1089 	 * @param string     $query_arg Optional. Key to check for nonce in `$_REQUEST` (since 2.5).
  1127 	 * @param int|string $action    The nonce action.
  1090 	 *                              Default '_wpnonce'.
  1128 	 * @param string     $query_arg Optional. Key to check for nonce in `$_REQUEST`. Default '_wpnonce'.
  1091 	 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
  1129 	 * @return int|false 1 if the nonce is valid and generated between 0-12 hours ago,
  1092 	 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
  1130 	 *                   2 if the nonce is valid and generated between 12-24 hours ago.
       
  1131 	 *                   False if the nonce is invalid.
  1093 	 */
  1132 	 */
  1094 	function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
  1133 	function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
  1095 		if ( -1 === $action ) {
  1134 		if ( -1 === $action ) {
  1096 			_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2.0' );
  1135 			_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2.0' );
  1097 		}
  1136 		}
  1130 	 * @param false|string $query_arg Optional. Key to check for the nonce in `$_REQUEST` (since 2.5). If false,
  1169 	 * @param false|string $query_arg Optional. Key to check for the nonce in `$_REQUEST` (since 2.5). If false,
  1131 	 *                                `$_REQUEST` values will be evaluated for '_ajax_nonce', and '_wpnonce'
  1170 	 *                                `$_REQUEST` values will be evaluated for '_ajax_nonce', and '_wpnonce'
  1132 	 *                                (in that order). Default false.
  1171 	 *                                (in that order). Default false.
  1133 	 * @param bool         $die       Optional. Whether to die early when the nonce cannot be verified.
  1172 	 * @param bool         $die       Optional. Whether to die early when the nonce cannot be verified.
  1134 	 *                                Default true.
  1173 	 *                                Default true.
  1135 	 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
  1174 	 * @return int|false 1 if the nonce is valid and generated between 0-12 hours ago,
  1136 	 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
  1175 	 *                   2 if the nonce is valid and generated between 12-24 hours ago.
       
  1176 	 *                   False if the nonce is invalid.
  1137 	 */
  1177 	 */
  1138 	function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
  1178 	function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
  1139 		if ( -1 == $action ) {
  1179 		if ( -1 == $action ) {
  1140 			_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '4.7' );
  1180 			_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '4.7' );
  1141 		}
  1181 		}
  1192 	 *         exit;
  1232 	 *         exit;
  1193 	 *     }
  1233 	 *     }
  1194 	 *
  1234 	 *
  1195 	 * @since 1.5.1
  1235 	 * @since 1.5.1
  1196 	 * @since 5.1.0 The `$x_redirect_by` parameter was added.
  1236 	 * @since 5.1.0 The `$x_redirect_by` parameter was added.
       
  1237 	 * @since 5.4.0 On invalid status codes, wp_die() is called.
  1197 	 *
  1238 	 *
  1198 	 * @global bool $is_IIS
  1239 	 * @global bool $is_IIS
  1199 	 *
  1240 	 *
  1200 	 * @param string $location      The path or URL to redirect to.
  1241 	 * @param string $location      The path or URL to redirect to.
  1201 	 * @param int    $status        Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
  1242 	 * @param int    $status        Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
  1227 
  1268 
  1228 		if ( ! $location ) {
  1269 		if ( ! $location ) {
  1229 			return false;
  1270 			return false;
  1230 		}
  1271 		}
  1231 
  1272 
       
  1273 		if ( $status < 300 || 399 < $status ) {
       
  1274 			wp_die( __( 'HTTP redirect status code must be a redirection code, 3xx.' ) );
       
  1275 		}
       
  1276 
  1232 		$location = wp_sanitize_redirect( $location );
  1277 		$location = wp_sanitize_redirect( $location );
  1233 
  1278 
  1234 		if ( ! $is_IIS && PHP_SAPI != 'cgi-fcgi' ) {
  1279 		if ( ! $is_IIS && 'cgi-fcgi' !== PHP_SAPI ) {
  1235 			status_header( $status ); // This causes problems on IIS and some FastCGI setups
  1280 			status_header( $status ); // This causes problems on IIS and some FastCGI setups.
  1236 		}
  1281 		}
  1237 
  1282 
  1238 		/**
  1283 		/**
  1239 		 * Filters the X-Redirect-By header.
  1284 		 * Filters the X-Redirect-By header.
  1240 		 *
  1285 		 *
  1265 	 *
  1310 	 *
  1266 	 * @param string $location The path to redirect to.
  1311 	 * @param string $location The path to redirect to.
  1267 	 * @return string Redirect-sanitized URL.
  1312 	 * @return string Redirect-sanitized URL.
  1268 	 */
  1313 	 */
  1269 	function wp_sanitize_redirect( $location ) {
  1314 	function wp_sanitize_redirect( $location ) {
       
  1315 		// Encode spaces.
       
  1316 		$location = str_replace( ' ', '%20', $location );
       
  1317 
  1270 		$regex    = '/
  1318 		$regex    = '/
  1271 		(
  1319 		(
  1272 			(?: [\xC2-\xDF][\x80-\xBF]        # double-byte sequences   110xxxxx 10xxxxxx
  1320 			(?: [\xC2-\xDF][\x80-\xBF]        # double-byte sequences   110xxxxx 10xxxxxx
  1273 			|   \xE0[\xA0-\xBF][\x80-\xBF]    # triple-byte sequences   1110xxxx 10xxxxxx * 2
  1321 			|   \xE0[\xA0-\xBF][\x80-\xBF]    # triple-byte sequences   1110xxxx 10xxxxxx * 2
  1274 			|   [\xE1-\xEC][\x80-\xBF]{2}
  1322 			|   [\xE1-\xEC][\x80-\xBF]{2}
  1281 		)/x';
  1329 		)/x';
  1282 		$location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
  1330 		$location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
  1283 		$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location );
  1331 		$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location );
  1284 		$location = wp_kses_no_null( $location );
  1332 		$location = wp_kses_no_null( $location );
  1285 
  1333 
  1286 		// remove %0d and %0a from location
  1334 		// Remove %0D and %0A from location.
  1287 		$strip = array( '%0d', '%0a', '%0D', '%0A' );
  1335 		$strip = array( '%0d', '%0a', '%0D', '%0A' );
  1288 		return _deep_replace( $strip, $location );
  1336 		return _deep_replace( $strip, $location );
  1289 	}
  1337 	}
  1290 
  1338 
  1291 	/**
  1339 	/**
  1334 	 * @since 5.1.0 The return value from wp_redirect() is now passed on, and the `$x_redirect_by` parameter was added.
  1382 	 * @since 5.1.0 The return value from wp_redirect() is now passed on, and the `$x_redirect_by` parameter was added.
  1335 	 *
  1383 	 *
  1336 	 * @param string $location      The path or URL to redirect to.
  1384 	 * @param string $location      The path or URL to redirect to.
  1337 	 * @param int    $status        Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
  1385 	 * @param int    $status        Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
  1338 	 * @param string $x_redirect_by Optional. The application doing the redirect. Default 'WordPress'.
  1386 	 * @param string $x_redirect_by Optional. The application doing the redirect. Default 'WordPress'.
  1339 	 * @return bool  $redirect False if the redirect was cancelled, true otherwise.
  1387 	 * @return bool False if the redirect was cancelled, true otherwise.
  1340 	 */
  1388 	 */
  1341 	function wp_safe_redirect( $location, $status = 302, $x_redirect_by = 'WordPress' ) {
  1389 	function wp_safe_redirect( $location, $status = 302, $x_redirect_by = 'WordPress' ) {
  1342 
  1390 
  1343 		// Need to look at the URL the way it will end up in wp_redirect()
  1391 		// Need to look at the URL the way it will end up in wp_redirect().
  1344 		$location = wp_sanitize_redirect( $location );
  1392 		$location = wp_sanitize_redirect( $location );
  1345 
  1393 
  1346 		/**
  1394 		/**
  1347 		 * Filters the redirect fallback URL for when the provided redirect is not safe (local).
  1395 		 * Filters the redirect fallback URL for when the provided redirect is not safe (local).
  1348 		 *
  1396 		 *
  1372 	 * @param string $location The redirect to validate
  1420 	 * @param string $location The redirect to validate
  1373 	 * @param string $default  The value to return if $location is not allowed
  1421 	 * @param string $default  The value to return if $location is not allowed
  1374 	 * @return string redirect-sanitized URL
  1422 	 * @return string redirect-sanitized URL
  1375 	 */
  1423 	 */
  1376 	function wp_validate_redirect( $location, $default = '' ) {
  1424 	function wp_validate_redirect( $location, $default = '' ) {
  1377 		$location = trim( $location, " \t\n\r\0\x08\x0B" );
  1425 		$location = wp_sanitize_redirect( trim( $location, " \t\n\r\0\x08\x0B" ) );
  1378 		// browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
  1426 		// Browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'.
  1379 		if ( substr( $location, 0, 2 ) == '//' ) {
  1427 		if ( '//' === substr( $location, 0, 2 ) ) {
  1380 			$location = 'http:' . $location;
  1428 			$location = 'http:' . $location;
  1381 		}
  1429 		}
  1382 
  1430 
  1383 		// In php 5 parse_url may fail if the URL query part contains http://, bug #38143
  1431 		// In PHP 5 parse_url() may fail if the URL query part contains 'http://'.
  1384 		$test = ( $cut = strpos( $location, '?' ) ) ? substr( $location, 0, $cut ) : $location;
  1432 		// See https://bugs.php.net/bug.php?id=38143
  1385 
  1433 		$cut  = strpos( $location, '?' );
  1386 		// @-operator is used to prevent possible warnings in PHP < 5.3.3.
  1434 		$test = $cut ? substr( $location, 0, $cut ) : $location;
  1387 		$lp = @parse_url( $test );
  1435 
  1388 
  1436 		$lp = parse_url( $test );
  1389 		// Give up if malformed URL
  1437 
       
  1438 		// Give up if malformed URL.
  1390 		if ( false === $lp ) {
  1439 		if ( false === $lp ) {
  1391 			return $default;
  1440 			return $default;
  1392 		}
  1441 		}
  1393 
  1442 
  1394 		// Allow only http and https schemes. No data:, etc.
  1443 		// Allow only 'http' and 'https' schemes. No 'data:', etc.
  1395 		if ( isset( $lp['scheme'] ) && ! ( 'http' == $lp['scheme'] || 'https' == $lp['scheme'] ) ) {
  1444 		if ( isset( $lp['scheme'] ) && ! ( 'http' === $lp['scheme'] || 'https' === $lp['scheme'] ) ) {
  1396 			return $default;
  1445 			return $default;
  1397 		}
  1446 		}
  1398 
  1447 
  1399 		if ( ! isset( $lp['host'] ) && ! empty( $lp['path'] ) && '/' !== $lp['path'][0] ) {
  1448 		if ( ! isset( $lp['host'] ) && ! empty( $lp['path'] ) && '/' !== $lp['path'][0] ) {
  1400 			$path = '';
  1449 			$path = '';
  1403 				$path = wp_normalize_path( $path );
  1452 				$path = wp_normalize_path( $path );
  1404 			}
  1453 			}
  1405 			$location = '/' . ltrim( $path . '/', '/' ) . $location;
  1454 			$location = '/' . ltrim( $path . '/', '/' ) . $location;
  1406 		}
  1455 		}
  1407 
  1456 
  1408 		// Reject if certain components are set but host is not. This catches urls like https:host.com for which parse_url does not set the host field.
  1457 		// Reject if certain components are set but host is not.
       
  1458 		// This catches URLs like https:host.com for which parse_url() does not set the host field.
  1409 		if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
  1459 		if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
  1410 			return $default;
  1460 			return $default;
  1411 		}
  1461 		}
  1412 
  1462 
  1413 		// Reject malformed components parse_url() can return on odd inputs.
  1463 		// Reject malformed components parse_url() can return on odd inputs.
  1418 		}
  1468 		}
  1419 
  1469 
  1420 		$wpp = parse_url( home_url() );
  1470 		$wpp = parse_url( home_url() );
  1421 
  1471 
  1422 		/**
  1472 		/**
  1423 		 * Filters the whitelist of hosts to redirect to.
  1473 		 * Filters the list of allowed hosts to redirect to.
  1424 		 *
  1474 		 *
  1425 		 * @since 2.3.0
  1475 		 * @since 2.3.0
  1426 		 *
  1476 		 *
  1427 		 * @param array       $hosts An array of allowed hosts.
  1477 		 * @param string[] $hosts An array of allowed host names.
  1428 		 * @param bool|string $host  The parsed host; empty if not isset.
  1478 		 * @param string   $host  The host name of the redirect destination; empty string if not set.
  1429 		 */
  1479 		 */
  1430 		$allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array( $wpp['host'] ), isset( $lp['host'] ) ? $lp['host'] : '' );
  1480 		$allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array( $wpp['host'] ), isset( $lp['host'] ) ? $lp['host'] : '' );
  1431 
  1481 
  1432 		if ( isset( $lp['host'] ) && ( ! in_array( $lp['host'], $allowed_hosts ) && $lp['host'] != strtolower( $wpp['host'] ) ) ) {
  1482 		if ( isset( $lp['host'] ) && ( ! in_array( $lp['host'], $allowed_hosts, true ) && strtolower( $wpp['host'] ) !== $lp['host'] ) ) {
  1433 			$location = $default;
  1483 			$location = $default;
  1434 		}
  1484 		}
  1435 
  1485 
  1436 		return $location;
  1486 		return $location;
  1437 	}
  1487 	}
  1441 	/**
  1491 	/**
  1442 	 * Notify an author (and/or others) of a comment/trackback/pingback on a post.
  1492 	 * Notify an author (and/or others) of a comment/trackback/pingback on a post.
  1443 	 *
  1493 	 *
  1444 	 * @since 1.0.0
  1494 	 * @since 1.0.0
  1445 	 *
  1495 	 *
  1446 	 * @param int|WP_Comment  $comment_id Comment ID or WP_Comment object.
  1496 	 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
  1447 	 * @param string          $deprecated Not used
  1497 	 * @param string         $deprecated Not used
  1448 	 * @return bool True on completion. False if no email addresses were specified.
  1498 	 * @return bool True on completion. False if no email addresses were specified.
  1449 	 */
  1499 	 */
  1450 	function wp_notify_postauthor( $comment_id, $deprecated = null ) {
  1500 	function wp_notify_postauthor( $comment_id, $deprecated = null ) {
  1451 		if ( null !== $deprecated ) {
  1501 		if ( null !== $deprecated ) {
  1452 			_deprecated_argument( __FUNCTION__, '3.8.0' );
  1502 			_deprecated_argument( __FUNCTION__, '3.8.0' );
  1472 		 * By default, only post authors are notified of comments. This filter allows
  1522 		 * By default, only post authors are notified of comments. This filter allows
  1473 		 * others to be added.
  1523 		 * others to be added.
  1474 		 *
  1524 		 *
  1475 		 * @since 3.7.0
  1525 		 * @since 3.7.0
  1476 		 *
  1526 		 *
  1477 		 * @param array $emails     An array of email addresses to receive a comment notification.
  1527 		 * @param string[] $emails     An array of email addresses to receive a comment notification.
  1478 		 * @param int   $comment_id The comment ID.
  1528 		 * @param int      $comment_id The comment ID.
  1479 		 */
  1529 		 */
  1480 		$emails = apply_filters( 'comment_notification_recipients', $emails, $comment->comment_ID );
  1530 		$emails = apply_filters( 'comment_notification_recipients', $emails, $comment->comment_ID );
  1481 		$emails = array_filter( $emails );
  1531 		$emails = array_filter( $emails );
  1482 
  1532 
  1483 		// If there are no addresses to send the comment to, bail.
  1533 		// If there are no addresses to send the comment to, bail.
  1500 		 *                         Default false.
  1550 		 *                         Default false.
  1501 		 * @param int  $comment_id The comment ID.
  1551 		 * @param int  $comment_id The comment ID.
  1502 		 */
  1552 		 */
  1503 		$notify_author = apply_filters( 'comment_notification_notify_author', false, $comment->comment_ID );
  1553 		$notify_author = apply_filters( 'comment_notification_notify_author', false, $comment->comment_ID );
  1504 
  1554 
  1505 		// The comment was left by the author
  1555 		// The comment was left by the author.
  1506 		if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
  1556 		if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
  1507 			unset( $emails[ $author->user_email ] );
  1557 			unset( $emails[ $author->user_email ] );
  1508 		}
  1558 		}
  1509 
  1559 
  1510 		// The author moderated a comment on their own post
  1560 		// The author moderated a comment on their own post.
  1511 		if ( $author && ! $notify_author && $post->post_author == get_current_user_id() ) {
  1561 		if ( $author && ! $notify_author && get_current_user_id() == $post->post_author ) {
  1512 			unset( $emails[ $author->user_email ] );
  1562 			unset( $emails[ $author->user_email ] );
  1513 		}
  1563 		}
  1514 
  1564 
  1515 		// The post author is no longer a member of the blog
  1565 		// The post author is no longer a member of the blog.
  1516 		if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
  1566 		if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
  1517 			unset( $emails[ $author->user_email ] );
  1567 			unset( $emails[ $author->user_email ] );
  1518 		}
  1568 		}
  1519 
  1569 
  1520 		// If there's no email to send the comment to, bail, otherwise flip array back around for use below
  1570 		// If there's no email to send the comment to, bail, otherwise flip array back around for use below.
  1521 		if ( ! count( $emails ) ) {
  1571 		if ( ! count( $emails ) ) {
  1522 			return false;
  1572 			return false;
  1523 		} else {
  1573 		} else {
  1524 			$emails = array_flip( $emails );
  1574 			$emails = array_flip( $emails );
  1525 		}
  1575 		}
  1526 
  1576 
  1527 		$switched_locale = switch_to_locale( get_locale() );
  1577 		$switched_locale = switch_to_locale( get_locale() );
  1528 
  1578 
  1529 		$comment_author_domain = @gethostbyaddr( $comment->comment_author_IP );
  1579 		$comment_author_domain = '';
  1530 
  1580 		if ( WP_Http::is_ip_address( $comment->comment_author_IP ) ) {
  1531 		// The blogname option is escaped with esc_html on the way into the database in sanitize_option
  1581 			$comment_author_domain = gethostbyaddr( $comment->comment_author_IP );
  1532 		// we want to reverse this for the plain text arena of emails.
  1582 		}
       
  1583 
       
  1584 		// The blogname option is escaped with esc_html() on the way into the database in sanitize_option().
       
  1585 		// We want to reverse this for the plain text arena of emails.
  1533 		$blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1586 		$blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1534 		$comment_content = wp_specialchars_decode( $comment->comment_content );
  1587 		$comment_content = wp_specialchars_decode( $comment->comment_content );
  1535 
  1588 
  1536 		switch ( $comment->comment_type ) {
  1589 		switch ( $comment->comment_type ) {
  1537 			case 'trackback':
  1590 			case 'trackback':
  1538 				/* translators: %s: post title */
  1591 				/* translators: %s: Post title. */
  1539 				$notify_message = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
  1592 				$notify_message = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
  1540 				/* translators: 1: trackback/pingback website name, 2: website IP address, 3: website hostname */
  1593 				/* translators: 1: Trackback/pingback website name, 2: Website IP address, 3: Website hostname. */
  1541 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1594 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1542 				/* translators: %s: trackback/pingback/comment author URL */
  1595 				/* translators: %s: Trackback/pingback/comment author URL. */
  1543 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1596 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1544 				/* translators: %s: comment text */
  1597 				/* translators: %s: Comment text. */
  1545 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1598 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1546 				$notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
  1599 				$notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
  1547 				/* translators: Trackback notification email subject. 1: Site title, 2: Post title */
  1600 				/* translators: Trackback notification email subject. 1: Site title, 2: Post title. */
  1548 				$subject = sprintf( __( '[%1$s] Trackback: "%2$s"' ), $blogname, $post->post_title );
  1601 				$subject = sprintf( __( '[%1$s] Trackback: "%2$s"' ), $blogname, $post->post_title );
  1549 				break;
  1602 				break;
       
  1603 
  1550 			case 'pingback':
  1604 			case 'pingback':
  1551 				/* translators: %s: post title */
  1605 				/* translators: %s: Post title. */
  1552 				$notify_message = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
  1606 				$notify_message = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
  1553 				/* translators: 1: trackback/pingback website name, 2: website IP address, 3: website hostname */
  1607 				/* translators: 1: Trackback/pingback website name, 2: Website IP address, 3: Website hostname. */
  1554 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1608 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1555 				/* translators: %s: trackback/pingback/comment author URL */
  1609 				/* translators: %s: Trackback/pingback/comment author URL. */
  1556 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1610 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1557 				/* translators: %s: comment text */
  1611 				/* translators: %s: Comment text. */
  1558 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1612 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1559 				$notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
  1613 				$notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
  1560 				/* translators: Pingback notification email subject. 1: Site title, 2: Post title */
  1614 				/* translators: Pingback notification email subject. 1: Site title, 2: Post title. */
  1561 				$subject = sprintf( __( '[%1$s] Pingback: "%2$s"' ), $blogname, $post->post_title );
  1615 				$subject = sprintf( __( '[%1$s] Pingback: "%2$s"' ), $blogname, $post->post_title );
  1562 				break;
  1616 				break;
  1563 			default: // Comments
  1617 
  1564 				/* translators: %s: post title */
  1618 			default: // Comments.
       
  1619 				/* translators: %s: Post title. */
  1565 				$notify_message = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
  1620 				$notify_message = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
  1566 				/* translators: 1: comment author's name, 2: comment author's IP address, 3: comment author's hostname */
  1621 				/* translators: 1: Comment author's name, 2: Comment author's IP address, 3: Comment author's hostname. */
  1567 				$notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1622 				$notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1568 				/* translators: %s: comment author email */
  1623 				/* translators: %s: Comment author email. */
  1569 				$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
  1624 				$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
  1570 				/* translators: %s: trackback/pingback/comment author URL */
  1625 				/* translators: %s: Trackback/pingback/comment author URL. */
  1571 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1626 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1572 				/* translators: %s: comment text */
  1627 
       
  1628 				if ( $comment->comment_parent && user_can( $post->post_author, 'edit_comment', $comment->comment_parent ) ) {
       
  1629 					/* translators: Comment moderation. %s: Parent comment edit URL. */
       
  1630 					$notify_message .= sprintf( __( 'In reply to: %s' ), admin_url( "comment.php?action=editcomment&c={$comment->comment_parent}#wpbody-content" ) ) . "\r\n";
       
  1631 				}
       
  1632 
       
  1633 				/* translators: %s: Comment text. */
  1573 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1634 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1574 				$notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
  1635 				$notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
  1575 				/* translators: Comment notification email subject. 1: Site title, 2: Post title */
  1636 				/* translators: Comment notification email subject. 1: Site title, 2: Post title. */
  1576 				$subject = sprintf( __( '[%1$s] Comment: "%2$s"' ), $blogname, $post->post_title );
  1637 				$subject = sprintf( __( '[%1$s] Comment: "%2$s"' ), $blogname, $post->post_title );
  1577 				break;
  1638 				break;
  1578 		}
  1639 		}
       
  1640 
  1579 		$notify_message .= get_permalink( $comment->comment_post_ID ) . "#comments\r\n\r\n";
  1641 		$notify_message .= get_permalink( $comment->comment_post_ID ) . "#comments\r\n\r\n";
       
  1642 		/* translators: %s: Comment URL. */
  1580 		$notify_message .= sprintf( __( 'Permalink: %s' ), get_comment_link( $comment ) ) . "\r\n";
  1643 		$notify_message .= sprintf( __( 'Permalink: %s' ), get_comment_link( $comment ) ) . "\r\n";
  1581 
  1644 
  1582 		if ( user_can( $post->post_author, 'edit_comment', $comment->comment_ID ) ) {
  1645 		if ( user_can( $post->post_author, 'edit_comment', $comment->comment_ID ) ) {
  1583 			if ( EMPTY_TRASH_DAYS ) {
  1646 			if ( EMPTY_TRASH_DAYS ) {
  1584 				/* translators: Comment moderation. %s: Comment action URL */
  1647 				/* translators: Comment moderation. %s: Comment action URL. */
  1585 				$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1648 				$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1586 			} else {
  1649 			} else {
  1587 				/* translators: Comment moderation. %s: Comment action URL */
  1650 				/* translators: Comment moderation. %s: Comment action URL. */
  1588 				$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1651 				$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1589 			}
  1652 			}
  1590 			/* translators: Comment moderation. %s: Comment action URL */
  1653 			/* translators: Comment moderation. %s: Comment action URL. */
  1591 			$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1654 			$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
  1592 		}
  1655 		}
  1593 
  1656 
  1594 		$wp_email = 'wordpress@' . preg_replace( '#^www\.#', '', strtolower( $_SERVER['SERVER_NAME'] ) );
  1657 		$wp_email = 'wordpress@' . preg_replace( '#^www\.#', '', wp_parse_url( network_home_url(), PHP_URL_HOST ) );
  1595 
  1658 
  1596 		if ( '' == $comment->comment_author ) {
  1659 		if ( '' === $comment->comment_author ) {
  1597 			$from = "From: \"$blogname\" <$wp_email>";
  1660 			$from = "From: \"$blogname\" <$wp_email>";
  1598 			if ( '' != $comment->comment_author_email ) {
  1661 			if ( '' !== $comment->comment_author_email ) {
  1599 				$reply_to = "Reply-To: $comment->comment_author_email";
  1662 				$reply_to = "Reply-To: $comment->comment_author_email";
  1600 			}
  1663 			}
  1601 		} else {
  1664 		} else {
  1602 			$from = "From: \"$comment->comment_author\" <$wp_email>";
  1665 			$from = "From: \"$comment->comment_author\" <$wp_email>";
  1603 			if ( '' != $comment->comment_author_email ) {
  1666 			if ( '' !== $comment->comment_author_email ) {
  1604 				$reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
  1667 				$reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
  1605 			}
  1668 			}
  1606 		}
  1669 		}
  1607 
  1670 
  1608 		$message_headers = "$from\n"
  1671 		$message_headers = "$from\n"
  1641 		 * @param int    $comment_id      Comment ID.
  1704 		 * @param int    $comment_id      Comment ID.
  1642 		 */
  1705 		 */
  1643 		$message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment->comment_ID );
  1706 		$message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment->comment_ID );
  1644 
  1707 
  1645 		foreach ( $emails as $email ) {
  1708 		foreach ( $emails as $email ) {
  1646 			@wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
  1709 			wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
  1647 		}
  1710 		}
  1648 
  1711 
  1649 		if ( $switched_locale ) {
  1712 		if ( $switched_locale ) {
  1650 			restore_previous_locale();
  1713 			restore_previous_locale();
  1651 		}
  1714 		}
  1698 			}
  1761 			}
  1699 		}
  1762 		}
  1700 
  1763 
  1701 		$switched_locale = switch_to_locale( get_locale() );
  1764 		$switched_locale = switch_to_locale( get_locale() );
  1702 
  1765 
  1703 		$comment_author_domain = @gethostbyaddr( $comment->comment_author_IP );
  1766 		$comment_author_domain = '';
  1704 		$comments_waiting      = $wpdb->get_var( "SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'" );
  1767 		if ( WP_Http::is_ip_address( $comment->comment_author_IP ) ) {
  1705 
  1768 			$comment_author_domain = gethostbyaddr( $comment->comment_author_IP );
  1706 		// The blogname option is escaped with esc_html on the way into the database in sanitize_option
  1769 		}
  1707 		// we want to reverse this for the plain text arena of emails.
  1770 
       
  1771 		$comments_waiting = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_approved = '0'" );
       
  1772 
       
  1773 		// The blogname option is escaped with esc_html() on the way into the database in sanitize_option().
       
  1774 		// We want to reverse this for the plain text arena of emails.
  1708 		$blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1775 		$blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1709 		$comment_content = wp_specialchars_decode( $comment->comment_content );
  1776 		$comment_content = wp_specialchars_decode( $comment->comment_content );
  1710 
  1777 
  1711 		switch ( $comment->comment_type ) {
  1778 		switch ( $comment->comment_type ) {
  1712 			case 'trackback':
  1779 			case 'trackback':
  1713 				/* translators: %s: post title */
  1780 				/* translators: %s: Post title. */
  1714 				$notify_message  = sprintf( __( 'A new trackback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1781 				$notify_message  = sprintf( __( 'A new trackback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1715 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1782 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1716 				/* translators: 1: trackback/pingback website name, 2: website IP address, 3: website hostname */
  1783 				/* translators: 1: Trackback/pingback website name, 2: Website IP address, 3: Website hostname. */
  1717 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1784 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1718 				/* translators: %s: trackback/pingback/comment author URL */
  1785 				/* translators: %s: Trackback/pingback/comment author URL. */
  1719 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1786 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1720 				$notify_message .= __( 'Trackback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
  1787 				$notify_message .= __( 'Trackback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
  1721 				break;
  1788 				break;
       
  1789 
  1722 			case 'pingback':
  1790 			case 'pingback':
  1723 				/* translators: %s: post title */
  1791 				/* translators: %s: Post title. */
  1724 				$notify_message  = sprintf( __( 'A new pingback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1792 				$notify_message  = sprintf( __( 'A new pingback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1725 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1793 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1726 				/* translators: 1: trackback/pingback website name, 2: website IP address, 3: website hostname */
  1794 				/* translators: 1: Trackback/pingback website name, 2: Website IP address, 3: Website hostname. */
  1727 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1795 				$notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1728 				/* translators: %s: trackback/pingback/comment author URL */
  1796 				/* translators: %s: Trackback/pingback/comment author URL. */
  1729 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1797 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1730 				$notify_message .= __( 'Pingback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
  1798 				$notify_message .= __( 'Pingback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
  1731 				break;
  1799 				break;
  1732 			default: // Comments
  1800 
  1733 				/* translators: %s: post title */
  1801 			default: // Comments.
       
  1802 				/* translators: %s: Post title. */
  1734 				$notify_message  = sprintf( __( 'A new comment on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1803 				$notify_message  = sprintf( __( 'A new comment on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
  1735 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1804 				$notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
  1736 				/* translators: 1: comment author's name, 2: comment author's IP address, 3: comment author's hostname */
  1805 				/* translators: 1: Comment author's name, 2: Comment author's IP address, 3: Comment author's hostname. */
  1737 				$notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1806 				$notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
  1738 				/* translators: %s: comment author email */
  1807 				/* translators: %s: Comment author email. */
  1739 				$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
  1808 				$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
  1740 				/* translators: %s: trackback/pingback/comment author URL */
  1809 				/* translators: %s: Trackback/pingback/comment author URL. */
  1741 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1810 				$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
  1742 				/* translators: %s: comment text */
  1811 
       
  1812 				if ( $comment->comment_parent ) {
       
  1813 					/* translators: Comment moderation. %s: Parent comment edit URL. */
       
  1814 					$notify_message .= sprintf( __( 'In reply to: %s' ), admin_url( "comment.php?action=editcomment&c={$comment->comment_parent}#wpbody-content" ) ) . "\r\n";
       
  1815 				}
       
  1816 
       
  1817 				/* translators: %s: Comment text. */
  1743 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1818 				$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
  1744 				break;
  1819 				break;
  1745 		}
  1820 		}
  1746 
  1821 
  1747 		/* translators: Comment moderation. %s: Comment action URL */
  1822 		/* translators: Comment moderation. %s: Comment action URL. */
  1748 		$notify_message .= sprintf( __( 'Approve it: %s' ), admin_url( "comment.php?action=approve&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1823 		$notify_message .= sprintf( __( 'Approve it: %s' ), admin_url( "comment.php?action=approve&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1749 
  1824 
  1750 		if ( EMPTY_TRASH_DAYS ) {
  1825 		if ( EMPTY_TRASH_DAYS ) {
  1751 			/* translators: Comment moderation. %s: Comment action URL */
  1826 			/* translators: Comment moderation. %s: Comment action URL. */
  1752 			$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1827 			$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1753 		} else {
  1828 		} else {
  1754 			/* translators: Comment moderation. %s: Comment action URL */
  1829 			/* translators: Comment moderation. %s: Comment action URL. */
  1755 			$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1830 			$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1756 		}
  1831 		}
  1757 
  1832 
  1758 		/* translators: Comment moderation. %s: Comment action URL */
  1833 		/* translators: Comment moderation. %s: Comment action URL. */
  1759 		$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1834 		$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment_id}#wpbody-content" ) ) . "\r\n";
  1760 
  1835 
  1761 		/* translators: Comment moderation. %s: Number of comments awaiting approval */
       
  1762 		$notify_message .= sprintf(
  1836 		$notify_message .= sprintf(
       
  1837 			/* translators: Comment moderation. %s: Number of comments awaiting approval. */
  1763 			_n(
  1838 			_n(
  1764 				'Currently %s comment is waiting for approval. Please visit the moderation panel:',
  1839 				'Currently %s comment is waiting for approval. Please visit the moderation panel:',
  1765 				'Currently %s comments are waiting for approval. Please visit the moderation panel:',
  1840 				'Currently %s comments are waiting for approval. Please visit the moderation panel:',
  1766 				$comments_waiting
  1841 				$comments_waiting
  1767 			),
  1842 			),
  1768 			number_format_i18n( $comments_waiting )
  1843 			number_format_i18n( $comments_waiting )
  1769 		) . "\r\n";
  1844 		) . "\r\n";
  1770 		$notify_message .= admin_url( 'edit-comments.php?comment_status=moderated#wpbody-content' ) . "\r\n";
  1845 		$notify_message .= admin_url( 'edit-comments.php?comment_status=moderated#wpbody-content' ) . "\r\n";
  1771 
  1846 
  1772 		/* translators: Comment moderation notification email subject. 1: Site name, 2: Post title */
  1847 		/* translators: Comment moderation notification email subject. 1: Site title, 2: Post title. */
  1773 		$subject         = sprintf( __( '[%1$s] Please moderate: "%2$s"' ), $blogname, $post->post_title );
  1848 		$subject         = sprintf( __( '[%1$s] Please moderate: "%2$s"' ), $blogname, $post->post_title );
  1774 		$message_headers = '';
  1849 		$message_headers = '';
  1775 
  1850 
  1776 		/**
  1851 		/**
  1777 		 * Filters the list of recipients for comment moderation emails.
  1852 		 * Filters the list of recipients for comment moderation emails.
  1778 		 *
  1853 		 *
  1779 		 * @since 3.7.0
  1854 		 * @since 3.7.0
  1780 		 *
  1855 		 *
  1781 		 * @param array $emails     List of email addresses to notify for comment moderation.
  1856 		 * @param string[] $emails     List of email addresses to notify for comment moderation.
  1782 		 * @param int   $comment_id Comment ID.
  1857 		 * @param int      $comment_id Comment ID.
  1783 		 */
  1858 		 */
  1784 		$emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
  1859 		$emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
  1785 
  1860 
  1786 		/**
  1861 		/**
  1787 		 * Filters the comment moderation email text.
  1862 		 * Filters the comment moderation email text.
  1812 		 * @param int    $comment_id      Comment ID.
  1887 		 * @param int    $comment_id      Comment ID.
  1813 		 */
  1888 		 */
  1814 		$message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
  1889 		$message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
  1815 
  1890 
  1816 		foreach ( $emails as $email ) {
  1891 		foreach ( $emails as $email ) {
  1817 			@wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
  1892 			wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
  1818 		}
  1893 		}
  1819 
  1894 
  1820 		if ( $switched_locale ) {
  1895 		if ( $switched_locale ) {
  1821 			restore_previous_locale();
  1896 			restore_previous_locale();
  1822 		}
  1897 		}
  1832 	 * @since 2.7.0
  1907 	 * @since 2.7.0
  1833 	 *
  1908 	 *
  1834 	 * @param WP_User $user User object.
  1909 	 * @param WP_User $user User object.
  1835 	 */
  1910 	 */
  1836 	function wp_password_change_notification( $user ) {
  1911 	function wp_password_change_notification( $user ) {
  1837 		// send a copy of password change notification to the admin
  1912 		// Send a copy of password change notification to the admin,
  1838 		// but check to see if it's the admin whose password we're changing, and skip this
  1913 		// but check to see if it's the admin whose password we're changing, and skip this.
  1839 		if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
  1914 		if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
  1840 			/* translators: %s: user name */
  1915 			/* translators: %s: User name. */
  1841 			$message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
  1916 			$message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
  1842 			// The blogname option is escaped with esc_html on the way into the database in sanitize_option
  1917 			// The blogname option is escaped with esc_html() on the way into the database in sanitize_option().
  1843 			// we want to reverse this for the plain text arena of emails.
  1918 			// We want to reverse this for the plain text arena of emails.
  1844 			$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1919 			$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1845 
  1920 
  1846 			$wp_password_change_notification_email = array(
  1921 			$wp_password_change_notification_email = array(
  1847 				'to'      => get_option( 'admin_email' ),
  1922 				'to'      => get_option( 'admin_email' ),
  1848 				/* translators: Password change notification email subject. %s: Site title */
  1923 				/* translators: Password change notification email subject. %s: Site title. */
  1849 				'subject' => __( '[%s] Password Changed' ),
  1924 				'subject' => __( '[%s] Password Changed' ),
  1850 				'message' => $message,
  1925 				'message' => $message,
  1851 				'headers' => '',
  1926 				'headers' => '',
  1852 			);
  1927 			);
  1853 
  1928 
  1888 	 * @since 2.0.0
  1963 	 * @since 2.0.0
  1889 	 * @since 4.3.0 The `$plaintext_pass` parameter was changed to `$notify`.
  1964 	 * @since 4.3.0 The `$plaintext_pass` parameter was changed to `$notify`.
  1890 	 * @since 4.3.1 The `$plaintext_pass` parameter was deprecated. `$notify` added as a third parameter.
  1965 	 * @since 4.3.1 The `$plaintext_pass` parameter was deprecated. `$notify` added as a third parameter.
  1891 	 * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
  1966 	 * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
  1892 	 *
  1967 	 *
  1893 	 * @global wpdb         $wpdb      WordPress database object for queries.
       
  1894 	 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
       
  1895 	 *
       
  1896 	 * @param int    $user_id    User ID.
  1968 	 * @param int    $user_id    User ID.
  1897 	 * @param null   $deprecated Not used (argument deprecated).
  1969 	 * @param null   $deprecated Not used (argument deprecated).
  1898 	 * @param string $notify     Optional. Type of notification that should happen. Accepts 'admin' or an empty
  1970 	 * @param string $notify     Optional. Type of notification that should happen. Accepts 'admin' or an empty
  1899 	 *                           string (admin only), 'user', or 'both' (admin and user). Default empty.
  1971 	 *                           string (admin only), 'user', or 'both' (admin and user). Default empty.
  1900 	 */
  1972 	 */
  1901 	function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
  1973 	function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
  1902 		if ( $deprecated !== null ) {
  1974 		if ( null !== $deprecated ) {
  1903 			_deprecated_argument( __FUNCTION__, '4.3.1' );
  1975 			_deprecated_argument( __FUNCTION__, '4.3.1' );
  1904 		}
  1976 		}
  1905 
  1977 
  1906 		// Accepts only 'user', 'admin' , 'both' or default '' as $notify
  1978 		// Accepts only 'user', 'admin' , 'both' or default '' as $notify.
  1907 		if ( ! in_array( $notify, array( 'user', 'admin', 'both', '' ), true ) ) {
  1979 		if ( ! in_array( $notify, array( 'user', 'admin', 'both', '' ), true ) ) {
  1908 			return;
  1980 			return;
  1909 		}
  1981 		}
  1910 
  1982 
  1911 		global $wpdb, $wp_hasher;
       
  1912 		$user = get_userdata( $user_id );
  1983 		$user = get_userdata( $user_id );
  1913 
  1984 
  1914 		// The blogname option is escaped with esc_html on the way into the database in sanitize_option
  1985 		// The blogname option is escaped with esc_html() on the way into the database in sanitize_option().
  1915 		// we want to reverse this for the plain text arena of emails.
  1986 		// We want to reverse this for the plain text arena of emails.
  1916 		$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1987 		$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  1917 
  1988 
  1918 		if ( 'user' !== $notify ) {
  1989 		if ( 'user' !== $notify ) {
  1919 			$switched_locale = switch_to_locale( get_locale() );
  1990 			$switched_locale = switch_to_locale( get_locale() );
  1920 
  1991 
  1921 			/* translators: %s: site title */
  1992 			/* translators: %s: Site title. */
  1922 			$message = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
  1993 			$message = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
  1923 			/* translators: %s: user login */
  1994 			/* translators: %s: User login. */
  1924 			$message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
  1995 			$message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
  1925 			/* translators: %s: user email address */
  1996 			/* translators: %s: User email address. */
  1926 			$message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
  1997 			$message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
  1927 
  1998 
  1928 			$wp_new_user_notification_email_admin = array(
  1999 			$wp_new_user_notification_email_admin = array(
  1929 				'to'      => get_option( 'admin_email' ),
  2000 				'to'      => get_option( 'admin_email' ),
  1930 				/* translators: New user registration notification email subject. %s: Site title */
  2001 				/* translators: New user registration notification email subject. %s: Site title. */
  1931 				'subject' => __( '[%s] New User Registration' ),
  2002 				'subject' => __( '[%s] New User Registration' ),
  1932 				'message' => $message,
  2003 				'message' => $message,
  1933 				'headers' => '',
  2004 				'headers' => '',
  1934 			);
  2005 			);
  1935 
  2006 
  1936 			/**
  2007 			/**
  1937 			 * Filters the contents of the new user notification email sent to the site admin.
  2008 			 * Filters the contents of the new user notification email sent to the site admin.
  1938 			 *
  2009 			 *
  1939 			 * @since 4.9.0
  2010 			 * @since 4.9.0
  1940 			 *
  2011 			 *
  1941 			 * @param array   $wp_new_user_notification_email {
  2012 			 * @param array   $wp_new_user_notification_email_admin {
  1942 			 *     Used to build wp_mail().
  2013 			 *     Used to build wp_mail().
  1943 			 *
  2014 			 *
  1944 			 *     @type string $to      The intended recipient - site admin email address.
  2015 			 *     @type string $to      The intended recipient - site admin email address.
  1945 			 *     @type string $subject The subject of the email.
  2016 			 *     @type string $subject The subject of the email.
  1946 			 *     @type string $message The body of the email.
  2017 			 *     @type string $message The body of the email.
  1949 			 * @param WP_User $user     User object for new user.
  2020 			 * @param WP_User $user     User object for new user.
  1950 			 * @param string  $blogname The site title.
  2021 			 * @param string  $blogname The site title.
  1951 			 */
  2022 			 */
  1952 			$wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
  2023 			$wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
  1953 
  2024 
  1954 			@wp_mail(
  2025 			wp_mail(
  1955 				$wp_new_user_notification_email_admin['to'],
  2026 				$wp_new_user_notification_email_admin['to'],
  1956 				wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
  2027 				wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
  1957 				$wp_new_user_notification_email_admin['message'],
  2028 				$wp_new_user_notification_email_admin['message'],
  1958 				$wp_new_user_notification_email_admin['headers']
  2029 				$wp_new_user_notification_email_admin['headers']
  1959 			);
  2030 			);
  1961 			if ( $switched_locale ) {
  2032 			if ( $switched_locale ) {
  1962 				restore_previous_locale();
  2033 				restore_previous_locale();
  1963 			}
  2034 			}
  1964 		}
  2035 		}
  1965 
  2036 
  1966 		// `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notification.
  2037 		// `$deprecated` was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notification.
  1967 		if ( 'admin' === $notify || ( empty( $deprecated ) && empty( $notify ) ) ) {
  2038 		if ( 'admin' === $notify || ( empty( $deprecated ) && empty( $notify ) ) ) {
  1968 			return;
  2039 			return;
  1969 		}
  2040 		}
  1970 
  2041 
  1971 		// Generate something random for a password reset key.
  2042 		$key = get_password_reset_key( $user );
  1972 		$key = wp_generate_password( 20, false );
  2043 		if ( is_wp_error( $key ) ) {
  1973 
  2044 			return;
  1974 		/** This action is documented in wp-login.php */
  2045 		}
  1975 		do_action( 'retrieve_password_key', $user->user_login, $key );
       
  1976 
       
  1977 		// Now insert the key, hashed, into the DB.
       
  1978 		if ( empty( $wp_hasher ) ) {
       
  1979 			require_once ABSPATH . WPINC . '/class-phpass.php';
       
  1980 			$wp_hasher = new PasswordHash( 8, true );
       
  1981 		}
       
  1982 		$hashed = time() . ':' . $wp_hasher->HashPassword( $key );
       
  1983 		$wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
       
  1984 
  2046 
  1985 		$switched_locale = switch_to_locale( get_user_locale( $user ) );
  2047 		$switched_locale = switch_to_locale( get_user_locale( $user ) );
  1986 
  2048 
  1987 		/* translators: %s: user login */
  2049 		/* translators: %s: User login. */
  1988 		$message  = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
  2050 		$message  = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
  1989 		$message .= __( 'To set your password, visit the following address:' ) . "\r\n\r\n";
  2051 		$message .= __( 'To set your password, visit the following address:' ) . "\r\n\r\n";
  1990 		$message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . ">\r\n\r\n";
  2052 		$message .= network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . "\r\n\r\n";
  1991 
  2053 
  1992 		$message .= wp_login_url() . "\r\n";
  2054 		$message .= wp_login_url() . "\r\n";
  1993 
  2055 
  1994 		$wp_new_user_notification_email = array(
  2056 		$wp_new_user_notification_email = array(
  1995 			'to'      => $user->user_email,
  2057 			'to'      => $user->user_email,
  1996 			/* translators: Login details notification email subject. %s: Site title */
  2058 			/* translators: Login details notification email subject. %s: Site title. */
  1997 			'subject' => __( '[%s] Login Details' ),
  2059 			'subject' => __( '[%s] Login Details' ),
  1998 			'message' => $message,
  2060 			'message' => $message,
  1999 			'headers' => '',
  2061 			'headers' => '',
  2000 		);
  2062 		);
  2001 
  2063 
  2030 	}
  2092 	}
  2031 endif;
  2093 endif;
  2032 
  2094 
  2033 if ( ! function_exists( 'wp_nonce_tick' ) ) :
  2095 if ( ! function_exists( 'wp_nonce_tick' ) ) :
  2034 	/**
  2096 	/**
  2035 	 * Get the time-dependent variable for nonce creation.
  2097 	 * Returns the time-dependent variable for nonce creation.
  2036 	 *
  2098 	 *
  2037 	 * A nonce has a lifespan of two ticks. Nonces in their second tick may be
  2099 	 * A nonce has a lifespan of two ticks. Nonces in their second tick may be
  2038 	 * updated, e.g. by autosave.
  2100 	 * updated, e.g. by autosave.
  2039 	 *
  2101 	 *
  2040 	 * @since 2.5.0
  2102 	 * @since 2.5.0
  2055 	}
  2117 	}
  2056 endif;
  2118 endif;
  2057 
  2119 
  2058 if ( ! function_exists( 'wp_verify_nonce' ) ) :
  2120 if ( ! function_exists( 'wp_verify_nonce' ) ) :
  2059 	/**
  2121 	/**
  2060 	 * Verify that correct nonce was used with time limit.
  2122 	 * Verifies that a correct security nonce was used with time limit.
  2061 	 *
  2123 	 *
  2062 	 * The user is given an amount of time to use the token, so therefore, since the
  2124 	 * A nonce is valid for 24 hours (by default).
  2063 	 * UID and $action remain the same, the independent variable is the time.
       
  2064 	 *
  2125 	 *
  2065 	 * @since 2.0.3
  2126 	 * @since 2.0.3
  2066 	 *
  2127 	 *
  2067 	 * @param string     $nonce  Nonce that was used in the form to verify
  2128 	 * @param string     $nonce  Nonce value that was used for verification, usually via a form field.
  2068 	 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
  2129 	 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
  2069 	 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
  2130 	 * @return int|false 1 if the nonce is valid and generated between 0-12 hours ago,
  2070 	 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
  2131 	 *                   2 if the nonce is valid and generated between 12-24 hours ago.
       
  2132 	 *                   False if the nonce is invalid.
  2071 	 */
  2133 	 */
  2072 	function wp_verify_nonce( $nonce, $action = -1 ) {
  2134 	function wp_verify_nonce( $nonce, $action = -1 ) {
  2073 		$nonce = (string) $nonce;
  2135 		$nonce = (string) $nonce;
  2074 		$user  = wp_get_current_user();
  2136 		$user  = wp_get_current_user();
  2075 		$uid   = (int) $user->ID;
  2137 		$uid   = (int) $user->ID;
  2090 		}
  2152 		}
  2091 
  2153 
  2092 		$token = wp_get_session_token();
  2154 		$token = wp_get_session_token();
  2093 		$i     = wp_nonce_tick();
  2155 		$i     = wp_nonce_tick();
  2094 
  2156 
  2095 		// Nonce generated 0-12 hours ago
  2157 		// Nonce generated 0-12 hours ago.
  2096 		$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
  2158 		$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
  2097 		if ( hash_equals( $expected, $nonce ) ) {
  2159 		if ( hash_equals( $expected, $nonce ) ) {
  2098 			return 1;
  2160 			return 1;
  2099 		}
  2161 		}
  2100 
  2162 
  2101 		// Nonce generated 12-24 hours ago
  2163 		// Nonce generated 12-24 hours ago.
  2102 		$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
  2164 		$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
  2103 		if ( hash_equals( $expected, $nonce ) ) {
  2165 		if ( hash_equals( $expected, $nonce ) ) {
  2104 			return 2;
  2166 			return 2;
  2105 		}
  2167 		}
  2106 
  2168 
  2114 		 * @param WP_User    $user   The current user object.
  2176 		 * @param WP_User    $user   The current user object.
  2115 		 * @param string     $token  The user's session token.
  2177 		 * @param string     $token  The user's session token.
  2116 		 */
  2178 		 */
  2117 		do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
  2179 		do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
  2118 
  2180 
  2119 		// Invalid nonce
  2181 		// Invalid nonce.
  2120 		return false;
  2182 		return false;
  2121 	}
  2183 	}
  2122 endif;
  2184 endif;
  2123 
  2185 
  2124 if ( ! function_exists( 'wp_create_nonce' ) ) :
  2186 if ( ! function_exists( 'wp_create_nonce' ) ) :
  2147 	}
  2209 	}
  2148 endif;
  2210 endif;
  2149 
  2211 
  2150 if ( ! function_exists( 'wp_salt' ) ) :
  2212 if ( ! function_exists( 'wp_salt' ) ) :
  2151 	/**
  2213 	/**
  2152 	 * Get salt to add to hashes.
  2214 	 * Returns a salt to add to hashes.
  2153 	 *
  2215 	 *
  2154 	 * Salts are created using secret keys. Secret keys are located in two places:
  2216 	 * Salts are created using secret keys. Secret keys are located in two places:
  2155 	 * in the database and in the wp-config.php file. The secret key in the database
  2217 	 * in the database and in the wp-config.php file. The secret key in the database
  2156 	 * is randomly generated and will be appended to the secret keys in wp-config.php.
  2218 	 * is randomly generated and will be appended to the secret keys in wp-config.php.
  2157 	 *
  2219 	 *
  2174 	 * common dictionary strings. The added values makes it harder to crack.
  2236 	 * common dictionary strings. The added values makes it harder to crack.
  2175 	 *
  2237 	 *
  2176 	 * @since 2.5.0
  2238 	 * @since 2.5.0
  2177 	 *
  2239 	 *
  2178 	 * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
  2240 	 * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
  2179 	 *
       
  2180 	 * @staticvar array $cached_salts
       
  2181 	 * @staticvar array $duplicated_keys
       
  2182 	 *
  2241 	 *
  2183 	 * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
  2242 	 * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
  2184 	 * @return string Salt value
  2243 	 * @return string Salt value
  2185 	 */
  2244 	 */
  2186 	function wp_salt( $scheme = 'auth' ) {
  2245 	function wp_salt( $scheme = 'auth' ) {
  2217 			'salt' => '',
  2276 			'salt' => '',
  2218 		);
  2277 		);
  2219 		if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
  2278 		if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
  2220 			$values['key'] = SECRET_KEY;
  2279 			$values['key'] = SECRET_KEY;
  2221 		}
  2280 		}
  2222 		if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
  2281 		if ( 'auth' === $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
  2223 			$values['salt'] = SECRET_SALT;
  2282 			$values['salt'] = SECRET_SALT;
  2224 		}
  2283 		}
  2225 
  2284 
  2226 		if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
  2285 		if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ), true ) ) {
  2227 			foreach ( array( 'key', 'salt' ) as $type ) {
  2286 			foreach ( array( 'key', 'salt' ) as $type ) {
  2228 				$const = strtoupper( "{$scheme}_{$type}" );
  2287 				$const = strtoupper( "{$scheme}_{$type}" );
  2229 				if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
  2288 				if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
  2230 					$values[ $type ] = constant( $const );
  2289 					$values[ $type ] = constant( $const );
  2231 				} elseif ( ! $values[ $type ] ) {
  2290 				} elseif ( ! $values[ $type ] ) {
  2287 	 */
  2346 	 */
  2288 	function wp_hash_password( $password ) {
  2347 	function wp_hash_password( $password ) {
  2289 		global $wp_hasher;
  2348 		global $wp_hasher;
  2290 
  2349 
  2291 		if ( empty( $wp_hasher ) ) {
  2350 		if ( empty( $wp_hasher ) ) {
  2292 			require_once( ABSPATH . WPINC . '/class-phpass.php' );
  2351 			require_once ABSPATH . WPINC . '/class-phpass.php';
  2293 			// By default, use the portable hash from phpass
  2352 			// By default, use the portable hash from phpass.
  2294 			$wp_hasher = new PasswordHash( 8, true );
  2353 			$wp_hasher = new PasswordHash( 8, true );
  2295 		}
  2354 		}
  2296 
  2355 
  2297 		return $wp_hasher->HashPassword( trim( $password ) );
  2356 		return $wp_hasher->HashPassword( trim( $password ) );
  2298 	}
  2357 	}
  2311 	 * instead use the other package password checking algorithm.
  2370 	 * instead use the other package password checking algorithm.
  2312 	 *
  2371 	 *
  2313 	 * @since 2.5.0
  2372 	 * @since 2.5.0
  2314 	 *
  2373 	 *
  2315 	 * @global PasswordHash $wp_hasher PHPass object used for checking the password
  2374 	 * @global PasswordHash $wp_hasher PHPass object used for checking the password
  2316 	 *  against the $hash + $password
  2375 	 *                                 against the $hash + $password
  2317 	 * @uses PasswordHash::CheckPassword
  2376 	 * @uses PasswordHash::CheckPassword
  2318 	 *
  2377 	 *
  2319 	 * @param string     $password Plaintext user's password
  2378 	 * @param string     $password Plaintext user's password
  2320 	 * @param string     $hash     Hash of the user's password to check against.
  2379 	 * @param string     $hash     Hash of the user's password to check against.
  2321 	 * @param string|int $user_id  Optional. User ID.
  2380 	 * @param string|int $user_id  Optional. User ID.
  2344 			 * @param string|int $user_id  User ID. Can be empty.
  2403 			 * @param string|int $user_id  User ID. Can be empty.
  2345 			 */
  2404 			 */
  2346 			return apply_filters( 'check_password', $check, $password, $hash, $user_id );
  2405 			return apply_filters( 'check_password', $check, $password, $hash, $user_id );
  2347 		}
  2406 		}
  2348 
  2407 
  2349 		// If the stored hash is longer than an MD5, presume the
  2408 		// If the stored hash is longer than an MD5,
  2350 		// new style phpass portable hash.
  2409 		// presume the new style phpass portable hash.
  2351 		if ( empty( $wp_hasher ) ) {
  2410 		if ( empty( $wp_hasher ) ) {
  2352 			require_once( ABSPATH . WPINC . '/class-phpass.php' );
  2411 			require_once ABSPATH . WPINC . '/class-phpass.php';
  2353 			// By default, use the portable hash from phpass
  2412 			// By default, use the portable hash from phpass.
  2354 			$wp_hasher = new PasswordHash( 8, true );
  2413 			$wp_hasher = new PasswordHash( 8, true );
  2355 		}
  2414 		}
  2356 
  2415 
  2357 		$check = $wp_hasher->CheckPassword( $password, $hash );
  2416 		$check = $wp_hasher->CheckPassword( $password, $hash );
  2358 
  2417 
  2393 
  2452 
  2394 		/**
  2453 		/**
  2395 		 * Filters the randomly-generated password.
  2454 		 * Filters the randomly-generated password.
  2396 		 *
  2455 		 *
  2397 		 * @since 3.0.0
  2456 		 * @since 3.0.0
  2398 		 *
  2457 		 * @since 5.3.0 Added the `$length`, `$special_chars`, and `$extra_special_chars` parameters.
  2399 		 * @param string $password The generated password.
  2458 		 *
  2400 		 */
  2459 		 * @param string $password            The generated password.
  2401 		return apply_filters( 'random_password', $password );
  2460 		 * @param int    $length              The length of password to generate.
       
  2461 		 * @param bool   $special_chars       Whether to include standard special characters.
       
  2462 		 * @param bool   $extra_special_chars Whether to include other special characters.
       
  2463 		 */
       
  2464 		return apply_filters( 'random_password', $password, $length, $special_chars, $extra_special_chars );
  2402 	}
  2465 	}
  2403 endif;
  2466 endif;
  2404 
  2467 
  2405 if ( ! function_exists( 'wp_rand' ) ) :
  2468 if ( ! function_exists( 'wp_rand' ) ) :
  2406 	/**
  2469 	/**
  2408 	 *
  2471 	 *
  2409 	 * @since 2.6.2
  2472 	 * @since 2.6.2
  2410 	 * @since 4.4.0 Uses PHP7 random_int() or the random_compat library if available.
  2473 	 * @since 4.4.0 Uses PHP7 random_int() or the random_compat library if available.
  2411 	 *
  2474 	 *
  2412 	 * @global string $rnd_value
  2475 	 * @global string $rnd_value
  2413 	 * @staticvar string $seed
       
  2414 	 * @staticvar bool $use_random_int_functionality
       
  2415 	 *
  2476 	 *
  2416 	 * @param int $min Lower limit for the generated number
  2477 	 * @param int $min Lower limit for the generated number
  2417 	 * @param int $max Upper limit for the generated number
  2478 	 * @param int $max Upper limit for the generated number
  2418 	 * @return int A random number between min and max
  2479 	 * @return int A random number between min and max
  2419 	 */
  2480 	 */
  2420 	function wp_rand( $min = 0, $max = 0 ) {
  2481 	function wp_rand( $min = 0, $max = 0 ) {
  2421 		global $rnd_value;
  2482 		global $rnd_value;
  2422 
  2483 
  2423 		// Some misconfigured 32bit environments (Entropy PHP, for example) truncate integers larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats.
  2484 		// Some misconfigured 32-bit environments (Entropy PHP, for example)
       
  2485 		// truncate integers larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats.
  2424 		$max_random_number = 3000000000 === 2147483647 ? (float) '4294967295' : 4294967295; // 4294967295 = 0xffffffff
  2486 		$max_random_number = 3000000000 === 2147483647 ? (float) '4294967295' : 4294967295; // 4294967295 = 0xffffffff
  2425 
  2487 
  2426 		// We only handle Ints, floats are truncated to their integer value.
  2488 		// We only handle ints, floats are truncated to their integer value.
  2427 		$min = (int) $min;
  2489 		$min = (int) $min;
  2428 		$max = (int) $max;
  2490 		$max = (int) $max;
  2429 
  2491 
  2430 		// Use PHP's CSPRNG, or a compatible method
  2492 		// Use PHP's CSPRNG, or a compatible method.
  2431 		static $use_random_int_functionality = true;
  2493 		static $use_random_int_functionality = true;
  2432 		if ( $use_random_int_functionality ) {
  2494 		if ( $use_random_int_functionality ) {
  2433 			try {
  2495 			try {
  2434 				$_max = ( 0 != $max ) ? $max : $max_random_number;
  2496 				$_max = ( 0 != $max ) ? $max : $max_random_number;
  2435 				// wp_rand() can accept arguments in either order, PHP cannot.
  2497 				// wp_rand() can accept arguments in either order, PHP cannot.
  2446 			} catch ( Exception $e ) {
  2508 			} catch ( Exception $e ) {
  2447 				$use_random_int_functionality = false;
  2509 				$use_random_int_functionality = false;
  2448 			}
  2510 			}
  2449 		}
  2511 		}
  2450 
  2512 
  2451 		// Reset $rnd_value after 14 uses
  2513 		// Reset $rnd_value after 14 uses.
  2452 		// 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
  2514 		// 32 (md5) + 40 (sha1) + 40 (sha1) / 8 = 14 random numbers from $rnd_value.
  2453 		if ( strlen( $rnd_value ) < 8 ) {
  2515 		if ( strlen( $rnd_value ) < 8 ) {
  2454 			if ( defined( 'WP_SETUP_CONFIG' ) ) {
  2516 			if ( defined( 'WP_SETUP_CONFIG' ) ) {
  2455 				static $seed = '';
  2517 				static $seed = '';
  2456 			} else {
  2518 			} else {
  2457 				$seed = get_transient( 'random_seed' );
  2519 				$seed = get_transient( 'random_seed' );
  2463 			if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
  2525 			if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
  2464 				set_transient( 'random_seed', $seed );
  2526 				set_transient( 'random_seed', $seed );
  2465 			}
  2527 			}
  2466 		}
  2528 		}
  2467 
  2529 
  2468 		// Take the first 8 digits for our value
  2530 		// Take the first 8 digits for our value.
  2469 		$value = substr( $rnd_value, 0, 8 );
  2531 		$value = substr( $rnd_value, 0, 8 );
  2470 
  2532 
  2471 		// Strip the first eight, leaving the remainder for the next call to wp_rand().
  2533 		// Strip the first eight, leaving the remainder for the next call to wp_rand().
  2472 		$rnd_value = substr( $rnd_value, 8 );
  2534 		$rnd_value = substr( $rnd_value, 8 );
  2473 
  2535 
  2474 		$value = abs( hexdec( $value ) );
  2536 		$value = abs( hexdec( $value ) );
  2475 
  2537 
  2476 		// Reduce the value to be within the min - max range
  2538 		// Reduce the value to be within the min - max range.
  2477 		if ( $max != 0 ) {
  2539 		if ( 0 != $max ) {
  2478 			$value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
  2540 			$value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
  2479 		}
  2541 		}
  2480 
  2542 
  2481 		return abs( intval( $value ) );
  2543 		return abs( intval( $value ) );
  2482 	}
  2544 	}
  2511 				'user_activation_key' => '',
  2573 				'user_activation_key' => '',
  2512 			),
  2574 			),
  2513 			array( 'ID' => $user_id )
  2575 			array( 'ID' => $user_id )
  2514 		);
  2576 		);
  2515 
  2577 
  2516 		wp_cache_delete( $user_id, 'users' );
  2578 		clean_user_cache( $user_id );
  2517 	}
  2579 	}
  2518 endif;
  2580 endif;
  2519 
  2581 
  2520 if ( ! function_exists( 'get_avatar' ) ) :
  2582 if ( ! function_exists( 'get_avatar' ) ) :
  2521 	/**
  2583 	/**
  2522 	 * Retrieve the avatar `<img>` tag for a user, email address, MD5 hash, comment, or post.
  2584 	 * Retrieve the avatar `<img>` tag for a user, email address, MD5 hash, comment, or post.
  2523 	 *
  2585 	 *
  2524 	 * @since 2.5.0
  2586 	 * @since 2.5.0
  2525 	 * @since 4.2.0 Optional `$args` parameter added.
  2587 	 * @since 4.2.0 Optional `$args` parameter added.
  2526 	 *
  2588 	 *
  2527 	 * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
  2589 	 * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
  2528 	 *                           user email, WP_User object, WP_Post object, or WP_Comment object.
  2590 	 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
  2529 	 * @param int    $size       Optional. Height and width of the avatar image file in pixels. Default 96.
  2591 	 * @param int    $size        Optional. Height and width of the avatar image file in pixels. Default 96.
  2530 	 * @param string $default    Optional. URL for the default image or a default type. Accepts '404'
  2592 	 * @param string $default     Optional. URL for the default image or a default type. Accepts '404'
  2531 	 *                           (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
  2593 	 *                            (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
  2532 	 *                           (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
  2594 	 *                            (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
  2533 	 *                           'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
  2595 	 *                            'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
  2534 	 *                           or 'gravatar_default' (the Gravatar logo). Default is the value of the
  2596 	 *                            or 'gravatar_default' (the Gravatar logo). Default is the value of the
  2535 	 *                           'avatar_default' option, with a fallback of 'mystery'.
  2597 	 *                            'avatar_default' option, with a fallback of 'mystery'.
  2536 	 * @param string $alt        Optional. Alternative text to use in &lt;img&gt; tag. Default empty.
  2598 	 * @param string $alt         Optional. Alternative text to use in img tag. Default empty.
  2537 	 * @param array  $args       {
  2599 	 * @param array  $args {
  2538 	 *     Optional. Extra arguments to retrieve the avatar.
  2600 	 *     Optional. Extra arguments to retrieve the avatar.
  2539 	 *
  2601 	 *
  2540 	 *     @type int          $height        Display height of the avatar in pixels. Defaults to $size.
  2602 	 *     @type int          $height        Display height of the avatar in pixels. Defaults to $size.
  2541 	 *     @type int          $width         Display width of the avatar in pixels. Defaults to $size.
  2603 	 *     @type int          $width         Display width of the avatar in pixels. Defaults to $size.
  2542 	 *     @type bool         $force_default Whether to always show the default image, never the Gravatar. Default false.
  2604 	 *     @type bool         $force_default Whether to always show the default image, never the Gravatar. Default false.
  2543 	 *     @type string       $rating        What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are
  2605 	 *     @type string       $rating        What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are
  2544 	 *                                       judged in that order. Default is the value of the 'avatar_rating' option.
  2606 	 *                                       judged in that order. Default is the value of the 'avatar_rating' option.
  2545 	 *     @type string       $scheme        URL scheme to use. See set_url_scheme() for accepted values.
  2607 	 *     @type string       $scheme        URL scheme to use. See set_url_scheme() for accepted values.
  2546 	 *                                       Default null.
  2608 	 *                                       Default null.
  2547 	 *     @type array|string $class         Array or string of additional classes to add to the &lt;img&gt; element.
  2609 	 *     @type array|string $class         Array or string of additional classes to add to the img element.
  2548 	 *                                       Default null.
  2610 	 *                                       Default null.
  2549 	 *     @type bool         $force_display Whether to always show the avatar - ignores the show_avatars option.
  2611 	 *     @type bool         $force_display Whether to always show the avatar - ignores the show_avatars option.
  2550 	 *                                       Default false.
  2612 	 *                                       Default false.
       
  2613 	 *     @type string       $loading       Value for the `loading` attribute.
       
  2614 	 *                                       Default null.
  2551 	 *     @type string       $extra_attr    HTML attributes to insert in the IMG element. Is not sanitized. Default empty.
  2615 	 *     @type string       $extra_attr    HTML attributes to insert in the IMG element. Is not sanitized. Default empty.
  2552 	 * }
  2616 	 * }
  2553 	 * @return false|string `<img>` tag for the user's avatar. False on failure.
  2617 	 * @return string|false `<img>` tag for the user's avatar. False on failure.
  2554 	 */
  2618 	 */
  2555 	function get_avatar( $id_or_email, $size = 96, $default = '', $alt = '', $args = null ) {
  2619 	function get_avatar( $id_or_email, $size = 96, $default = '', $alt = '', $args = null ) {
  2556 		$defaults = array(
  2620 		$defaults = array(
  2557 			// get_avatar_data() args.
  2621 			// get_avatar_data() args.
  2558 			'size'          => 96,
  2622 			'size'          => 96,
  2563 			'rating'        => get_option( 'avatar_rating' ),
  2627 			'rating'        => get_option( 'avatar_rating' ),
  2564 			'scheme'        => null,
  2628 			'scheme'        => null,
  2565 			'alt'           => '',
  2629 			'alt'           => '',
  2566 			'class'         => null,
  2630 			'class'         => null,
  2567 			'force_display' => false,
  2631 			'force_display' => false,
       
  2632 			'loading'       => null,
  2568 			'extra_attr'    => '',
  2633 			'extra_attr'    => '',
  2569 		);
  2634 		);
       
  2635 
       
  2636 		if ( wp_lazy_loading_enabled( 'img', 'get_avatar' ) ) {
       
  2637 			$defaults['loading'] = 'lazy';
       
  2638 		}
  2570 
  2639 
  2571 		if ( empty( $args ) ) {
  2640 		if ( empty( $args ) ) {
  2572 			$args = array();
  2641 			$args = array();
  2573 		}
  2642 		}
  2574 
  2643 
  2588 		if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
  2657 		if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
  2589 			$id_or_email = get_comment( $id_or_email );
  2658 			$id_or_email = get_comment( $id_or_email );
  2590 		}
  2659 		}
  2591 
  2660 
  2592 		/**
  2661 		/**
  2593 		 * Filters whether to retrieve the avatar URL early.
  2662 		 * Allows the HTML for a user's avatar to be returned early.
  2594 		 *
  2663 		 *
  2595 		 * Passing a non-null value will effectively short-circuit get_avatar(), passing
  2664 		 * Passing a non-null value will effectively short-circuit get_avatar(), passing
  2596 		 * the value through the {@see 'get_avatar'} filter and returning early.
  2665 		 * the value through the {@see 'get_avatar'} filter and returning early.
  2597 		 *
  2666 		 *
  2598 		 * @since 4.2.0
  2667 		 * @since 4.2.0
  2599 		 *
  2668 		 *
  2600 		 * @param string $avatar      HTML for the user's avatar. Default null.
  2669 		 * @param string|null $avatar      HTML for the user's avatar. Default null.
  2601 		 * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
  2670 		 * @param mixed       $id_or_email The avatar to retrieve. Accepts a user_id, Gravatar MD5 hash,
  2602 		 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
  2671 		 *                                 user email, WP_User object, WP_Post object, or WP_Comment object.
  2603 		 * @param array  $args        Arguments passed to get_avatar_url(), after processing.
  2672 		 * @param array       $args        Arguments passed to get_avatar_url(), after processing.
  2604 		 */
  2673 		 */
  2605 		$avatar = apply_filters( 'pre_get_avatar', null, $id_or_email, $args );
  2674 		$avatar = apply_filters( 'pre_get_avatar', null, $id_or_email, $args );
  2606 
  2675 
  2607 		if ( ! is_null( $avatar ) ) {
  2676 		if ( ! is_null( $avatar ) ) {
  2608 			/** This filter is documented in wp-includes/pluggable.php */
  2677 			/** This filter is documented in wp-includes/pluggable.php */
  2633 			if ( is_array( $args['class'] ) ) {
  2702 			if ( is_array( $args['class'] ) ) {
  2634 				$class = array_merge( $class, $args['class'] );
  2703 				$class = array_merge( $class, $args['class'] );
  2635 			} else {
  2704 			} else {
  2636 				$class[] = $args['class'];
  2705 				$class[] = $args['class'];
  2637 			}
  2706 			}
       
  2707 		}
       
  2708 
       
  2709 		// Add `loading` attribute.
       
  2710 		$extra_attr = $args['extra_attr'];
       
  2711 		$loading    = $args['loading'];
       
  2712 
       
  2713 		if ( in_array( $loading, array( 'lazy', 'eager' ), true ) && ! preg_match( '/\bloading\s*=/', $extra_attr ) ) {
       
  2714 			if ( ! empty( $extra_attr ) ) {
       
  2715 				$extra_attr .= ' ';
       
  2716 			}
       
  2717 
       
  2718 			$extra_attr .= "loading='{$loading}'";
  2638 		}
  2719 		}
  2639 
  2720 
  2640 		$avatar = sprintf(
  2721 		$avatar = sprintf(
  2641 			"<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
  2722 			"<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
  2642 			esc_attr( $args['alt'] ),
  2723 			esc_attr( $args['alt'] ),
  2643 			esc_url( $url ),
  2724 			esc_url( $url ),
  2644 			esc_url( $url2x ) . ' 2x',
  2725 			esc_url( $url2x ) . ' 2x',
  2645 			esc_attr( join( ' ', $class ) ),
  2726 			esc_attr( join( ' ', $class ) ),
  2646 			(int) $args['height'],
  2727 			(int) $args['height'],
  2647 			(int) $args['width'],
  2728 			(int) $args['width'],
  2648 			$args['extra_attr']
  2729 			$extra_attr
  2649 		);
  2730 		);
  2650 
  2731 
  2651 		/**
  2732 		/**
  2652 		 * Filters the avatar to retrieve.
  2733 		 * Filters the HTML for a user's avatar.
  2653 		 *
  2734 		 *
  2654 		 * @since 2.5.0
  2735 		 * @since 2.5.0
  2655 		 * @since 4.2.0 The `$args` parameter was added.
  2736 		 * @since 4.2.0 The `$args` parameter was added.
  2656 		 *
  2737 		 *
  2657 		 * @param string $avatar      &lt;img&gt; tag for the user's avatar.
  2738 		 * @param string $avatar      HTML for the user's avatar.
  2658 		 * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
  2739 		 * @param mixed  $id_or_email The avatar to retrieve. Accepts a user_id, Gravatar MD5 hash,
  2659 		 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
  2740 		 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
  2660 		 * @param int    $size        Square avatar width and height in pixels to retrieve.
  2741 		 * @param int    $size        Square avatar width and height in pixels to retrieve.
  2661 		 * @param string $default     URL for the default image or a default type. Accepts '404', 'retro', 'monsterid',
  2742 		 * @param string $default     URL for the default image or a default type. Accepts '404', 'retro', 'monsterid',
  2662 		 *                            'wavatar', 'indenticon','mystery' (or 'mm', or 'mysteryman'), 'blank', or 'gravatar_default'.
  2743 		 *                            'wavatar', 'indenticon', 'mystery', 'mm', 'mysteryman', 'blank', or 'gravatar_default'.
  2663 		 *                            Default is the value of the 'avatar_default' option, with a fallback of 'mystery'.
  2744 		 *                            Default is the value of the 'avatar_default' option, with a fallback of 'mystery'.
  2664 		 * @param string $alt         Alternative text to use in the avatar image tag. Default empty.
  2745 		 * @param string $alt         Alternative text to use in the avatar image tag. Default empty.
  2665 		 * @param array  $args        Arguments passed to get_avatar_data(), after processing.
  2746 		 * @param array  $args        Arguments passed to get_avatar_data(), after processing.
  2666 		 */
  2747 		 */
  2667 		return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
  2748 		return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
  2674 	 *
  2755 	 *
  2675 	 * The Diff is available for getting the changes between versions. The output is
  2756 	 * The Diff is available for getting the changes between versions. The output is
  2676 	 * HTML, so the primary use is for displaying the changes. If the two strings
  2757 	 * HTML, so the primary use is for displaying the changes. If the two strings
  2677 	 * are equivalent, then an empty string will be returned.
  2758 	 * are equivalent, then an empty string will be returned.
  2678 	 *
  2759 	 *
  2679 	 * The arguments supported and can be changed are listed below.
       
  2680 	 *
       
  2681 	 * 'title' : Default is an empty string. Titles the diff in a manner compatible
       
  2682 	 *      with the output.
       
  2683 	 * 'title_left' : Default is an empty string. Change the HTML to the left of the
       
  2684 	 *      title.
       
  2685 	 * 'title_right' : Default is an empty string. Change the HTML to the right of
       
  2686 	 *      the title.
       
  2687 	 *
       
  2688 	 * @since 2.6.0
  2760 	 * @since 2.6.0
  2689 	 *
  2761 	 *
  2690 	 * @see wp_parse_args() Used to change defaults to user defined settings.
  2762 	 * @see wp_parse_args() Used to change defaults to user defined settings.
  2691 	 * @uses Text_Diff
  2763 	 * @uses Text_Diff
  2692 	 * @uses WP_Text_Diff_Renderer_Table
  2764 	 * @uses WP_Text_Diff_Renderer_Table
  2693 	 *
  2765 	 *
  2694 	 * @param string       $left_string  "old" (left) version of string
  2766 	 * @param string       $left_string  "old" (left) version of string
  2695 	 * @param string       $right_string "new" (right) version of string
  2767 	 * @param string       $right_string "new" (right) version of string
  2696 	 * @param string|array $args         Optional. Change 'title', 'title_left', and 'title_right' defaults.
  2768 	 * @param string|array $args {
       
  2769 	 *     Associative array of options to pass to WP_Text_Diff_Renderer_Table().
       
  2770 	 *
       
  2771 	 *     @type string $title           Titles the diff in a manner compatible
       
  2772 	 *                                   with the output. Default empty.
       
  2773 	 *     @type string $title_left      Change the HTML to the left of the title.
       
  2774 	 *                                   Default empty.
       
  2775 	 *     @type string $title_right     Change the HTML to the right of the title.
       
  2776 	 *                                   Default empty.
       
  2777 	 *     @type bool   $show_split_view True for split view (two columns), false for
       
  2778 	 *                                   un-split view (single column). Default true.
       
  2779 	 * }
  2697 	 * @return string Empty string if strings are equivalent or HTML with differences.
  2780 	 * @return string Empty string if strings are equivalent or HTML with differences.
  2698 	 */
  2781 	 */
  2699 	function wp_text_diff( $left_string, $right_string, $args = null ) {
  2782 	function wp_text_diff( $left_string, $right_string, $args = null ) {
  2700 		$defaults = array(
  2783 		$defaults = array(
  2701 			'title'       => '',
  2784 			'title'           => '',
  2702 			'title_left'  => '',
  2785 			'title_left'      => '',
  2703 			'title_right' => '',
  2786 			'title_right'     => '',
       
  2787 			'show_split_view' => true,
  2704 		);
  2788 		);
  2705 		$args     = wp_parse_args( $args, $defaults );
  2789 		$args     = wp_parse_args( $args, $defaults );
  2706 
  2790 
  2707 		if ( ! class_exists( 'WP_Text_Diff_Renderer_Table', false ) ) {
  2791 		if ( ! class_exists( 'WP_Text_Diff_Renderer_Table', false ) ) {
  2708 			require( ABSPATH . WPINC . '/wp-diff.php' );
  2792 			require ABSPATH . WPINC . '/wp-diff.php';
  2709 		}
  2793 		}
  2710 
  2794 
  2711 		$left_string  = normalize_whitespace( $left_string );
  2795 		$left_string  = normalize_whitespace( $left_string );
  2712 		$right_string = normalize_whitespace( $right_string );
  2796 		$right_string = normalize_whitespace( $right_string );
  2713 
  2797 
  2749 		$r .= '</table>';
  2833 		$r .= '</table>';
  2750 
  2834 
  2751 		return $r;
  2835 		return $r;
  2752 	}
  2836 	}
  2753 endif;
  2837 endif;
  2754