Make WordPress Core


Ignore:
Timestamp:
11/30/2017 11:09:33 PM (6 years ago)
Author:
pento
Message:

Code is Poetry.
WordPress' code just... wasn't.
This is now dealt with.

Props jrf, pento, netweb, GaryJ, jdgrimes, westonruter, Greg Sherwood from PHPCS, and everyone who's ever contributed to WPCS and PHPCS.
Fixes #41057.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/pluggable.php

    r42206 r42343  
    77 */
    88
    9 if ( !function_exists('wp_set_current_user') ) :
    10 /**
    11  * Changes the current user by ID or name.
    12  *
    13  * Set $id to null and specify a name if you do not know a user's ID.
    14  *
    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
    17  * actions on users who aren't signed in.
    18  *
    19  * @since 2.0.3
    20  * @global WP_User $current_user The current user object which holds the user data.
    21  *
    22  * @param int    $id   User ID
    23  * @param string $name User's username
    24  * @return WP_User Current user User object
    25  */
    26 function wp_set_current_user($id, $name = '') {
    27     global $current_user;
    28 
    29     // If `$id` matches the user who's already current, there's nothing to do.
    30     if ( isset( $current_user )
     9if ( ! function_exists( 'wp_set_current_user' ) ) :
     10    /**
     11    * Changes the current user by ID or name.
     12    *
     13    * Set $id to null and specify a name if you do not know a user's ID.
     14    *
     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
     17    * actions on users who aren't signed in.
     18    *
     19    * @since 2.0.3
     20    * @global WP_User $current_user The current user object which holds the user data.
     21    *
     22    * @param int    $id   User ID
     23    * @param string $name User's username
     24    * @return WP_User Current user User object
     25    */
     26    function wp_set_current_user( $id, $name = '' ) {
     27        global $current_user;
     28
     29        // If `$id` matches the user who's already current, there's nothing to do.
     30        if ( isset( $current_user )
    3131        && ( $current_user instanceof WP_User )
    3232        && ( $id == $current_user->ID )
    3333        && ( null !== $id )
    34     ) {
     34        ) {
     35            return $current_user;
     36        }
     37
     38        $current_user = new WP_User( $id, $name );
     39
     40        setup_userdata( $current_user->ID );
     41
     42        /**
     43         * Fires after the current user is set.
     44         *
     45         * @since 2.0.1
     46         */
     47        do_action( 'set_current_user' );
     48
    3549        return $current_user;
    3650    }
    37 
    38     $current_user = new WP_User( $id, $name );
    39 
    40     setup_userdata( $current_user->ID );
    41 
    42     /**
    43      * Fires after the current user is set.
    44      *
    45      * @since 2.0.1
    46      */
    47     do_action( 'set_current_user' );
    48 
    49     return $current_user;
    50 }
    51 endif;
    52 
    53 if ( !function_exists('wp_get_current_user') ) :
    54 /**
    55  * Retrieve the current user object.
    56  *
    57  * Will set the current user, if the current user is not set. The current user
    58  * will be set to the logged-in person. If no user is logged-in, then it will
    59  * set the current user to 0, which is invalid and won't have any permissions.
    60  *
    61  * @since 2.0.3
    62  *
    63  * @see _wp_get_current_user()
    64  * @global WP_User $current_user Checks if the current user is set.
    65  *
    66  * @return WP_User Current WP_User instance.
    67  */
    68 function wp_get_current_user() {
    69     return _wp_get_current_user();
    70 }
    71 endif;
    72 
    73 if ( !function_exists('get_userdata') ) :
    74 /**
    75  * Retrieve user info by user ID.
    76  *
    77  * @since 0.71
    78  *
    79  * @param int $user_id User ID
    80  * @return WP_User|false WP_User object on success, false on failure.
    81  */
    82 function get_userdata( $user_id ) {
    83     return get_user_by( 'id', $user_id );
    84 }
    85 endif;
    86 
    87 if ( !function_exists('get_user_by') ) :
    88 /**
    89  * Retrieve user info by a given field
    90  *
    91  * @since 2.8.0
    92  * @since 4.4.0 Added 'ID' as an alias of 'id' for the `$field` parameter.
    93  *
    94  * @param string     $field The field to retrieve the user with. id | ID | slug | email | login.
    95  * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
    96  * @return WP_User|false WP_User object on success, false on failure.
    97  */
    98 function get_user_by( $field, $value ) {
    99     $userdata = WP_User::get_data_by( $field, $value );
    100 
    101     if ( !$userdata )
    102         return false;
    103 
    104     $user = new WP_User;
    105     $user->init( $userdata );
    106 
    107     return $user;
    108 }
    109 endif;
    110 
    111 if ( !function_exists('cache_users') ) :
    112 /**
    113  * Retrieve info for user lists to prevent multiple queries by get_userdata()
    114  *
    115  * @since 3.0.0
    116  *
    117  * @global wpdb $wpdb WordPress database abstraction object.
    118  *
    119  * @param array $user_ids User ID numbers list
    120  */
    121 function cache_users( $user_ids ) {
    122     global $wpdb;
    123 
    124     $clean = _get_non_cached_ids( $user_ids, 'users' );
    125 
    126     if ( empty( $clean ) )
    127         return;
    128 
    129     $list = implode( ',', $clean );
    130 
    131     $users = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($list)" );
    132 
    133     $ids = array();
    134     foreach ( $users as $user ) {
    135         update_user_caches( $user );
    136         $ids[] = $user->ID;
    137     }
    138     update_meta_cache( 'user', $ids );
    139 }
    140 endif;
    141 
    142 if ( !function_exists( 'wp_mail' ) ) :
    143 /**
    144  * Send mail, similar to PHP's mail
    145  *
    146  * A true return value does not automatically mean that the user received the
    147  * email successfully. It just only means that the method used was able to
    148  * process the request without any errors.
    149  *
    150  * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
    151  * creating a from address like 'Name <email@address.com>' when both are set. If
    152  * just 'wp_mail_from' is set, then just the email address will be used with no
    153  * name.
    154  *
    155  * The default content type is 'text/plain' which does not allow using HTML.
    156  * However, you can set the content type of the email by using the
    157  * {@see 'wp_mail_content_type'} filter.
    158  *
    159  * The default charset is based on the charset used on the blog. The charset can
    160  * be set using the {@see 'wp_mail_charset'} filter.
    161  *
    162  * @since 1.2.1
    163  *
    164  * @global PHPMailer $phpmailer
    165  *
    166  * @param string|array $to          Array or comma-separated list of email addresses to send message.
    167  * @param string       $subject     Email subject
    168  * @param string       $message     Message contents
    169  * @param string|array $headers     Optional. Additional headers.
    170  * @param string|array $attachments Optional. Files to attach.
    171  * @return bool Whether the email contents were sent successfully.
    172  */
    173 function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
    174     // Compact the input, apply the filters, and extract them back out
    175 
    176     /**
    177      * Filters the wp_mail() arguments.
    178      *
    179      * @since 2.2.0
    180      *
    181      * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
    182      *                    subject, message, headers, and attachments values.
    183      */
    184     $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
    185 
    186     if ( isset( $atts['to'] ) ) {
    187         $to = $atts['to'];
    188     }
    189 
    190     if ( !is_array( $to ) ) {
    191         $to = explode( ',', $to );
    192     }
    193 
    194     if ( isset( $atts['subject'] ) ) {
    195         $subject = $atts['subject'];
    196     }
    197 
    198     if ( isset( $atts['message'] ) ) {
    199         $message = $atts['message'];
    200     }
    201 
    202     if ( isset( $atts['headers'] ) ) {
    203         $headers = $atts['headers'];
    204     }
    205 
    206     if ( isset( $atts['attachments'] ) ) {
    207         $attachments = $atts['attachments'];
    208     }
    209 
    210     if ( ! is_array( $attachments ) ) {
    211         $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
    212     }
    213     global $phpmailer;
    214 
    215     // (Re)create it, if it's gone missing
    216     if ( ! ( $phpmailer instanceof PHPMailer ) ) {
    217         require_once ABSPATH . WPINC . '/class-phpmailer.php';
    218         require_once ABSPATH . WPINC . '/class-smtp.php';
    219         $phpmailer = new PHPMailer( true );
    220     }
    221 
    222     // Headers
    223     $cc = $bcc = $reply_to = array();
    224 
    225     if ( empty( $headers ) ) {
    226         $headers = array();
    227     } else {
    228         if ( !is_array( $headers ) ) {
    229             // Explode the headers out, so this function can take both
    230             // string headers and an array of headers.
    231             $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
     51endif;
     52
     53if ( ! function_exists( 'wp_get_current_user' ) ) :
     54    /**
     55     * Retrieve the current user object.
     56     *
     57     * Will set the current user, if the current user is not set. The current user
     58     * will be set to the logged-in person. If no user is logged-in, then it will
     59     * set the current user to 0, which is invalid and won't have any permissions.
     60     *
     61     * @since 2.0.3
     62     *
     63     * @see _wp_get_current_user()
     64     * @global WP_User $current_user Checks if the current user is set.
     65     *
     66     * @return WP_User Current WP_User instance.
     67     */
     68    function wp_get_current_user() {
     69        return _wp_get_current_user();
     70    }
     71endif;
     72
     73if ( ! function_exists( 'get_userdata' ) ) :
     74    /**
     75     * Retrieve user info by user ID.
     76     *
     77     * @since 0.71
     78     *
     79     * @param int $user_id User ID
     80     * @return WP_User|false WP_User object on success, false on failure.
     81     */
     82    function get_userdata( $user_id ) {
     83        return get_user_by( 'id', $user_id );
     84    }
     85endif;
     86
     87if ( ! function_exists( 'get_user_by' ) ) :
     88    /**
     89     * Retrieve user info by a given field
     90     *
     91     * @since 2.8.0
     92     * @since 4.4.0 Added 'ID' as an alias of 'id' for the `$field` parameter.
     93     *
     94     * @param string     $field The field to retrieve the user with. id | ID | slug | email | login.
     95     * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
     96     * @return WP_User|false WP_User object on success, false on failure.
     97     */
     98    function get_user_by( $field, $value ) {
     99        $userdata = WP_User::get_data_by( $field, $value );
     100
     101        if ( ! $userdata ) {
     102            return false;
     103        }
     104
     105        $user = new WP_User;
     106        $user->init( $userdata );
     107
     108        return $user;
     109    }
     110endif;
     111
     112if ( ! function_exists( 'cache_users' ) ) :
     113    /**
     114     * Retrieve info for user lists to prevent multiple queries by get_userdata()
     115     *
     116     * @since 3.0.0
     117     *
     118     * @global wpdb $wpdb WordPress database abstraction object.
     119     *
     120     * @param array $user_ids User ID numbers list
     121     */
     122    function cache_users( $user_ids ) {
     123        global $wpdb;
     124
     125        $clean = _get_non_cached_ids( $user_ids, 'users' );
     126
     127        if ( empty( $clean ) ) {
     128            return;
     129        }
     130
     131        $list = implode( ',', $clean );
     132
     133        $users = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($list)" );
     134
     135        $ids = array();
     136        foreach ( $users as $user ) {
     137            update_user_caches( $user );
     138            $ids[] = $user->ID;
     139        }
     140        update_meta_cache( 'user', $ids );
     141    }
     142endif;
     143
     144if ( ! function_exists( 'wp_mail' ) ) :
     145    /**
     146     * Send mail, similar to PHP's mail
     147     *
     148     * 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     * process the request without any errors.
     151     *
     152     * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
     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
     159     * {@see 'wp_mail_content_type'} filter.
     160     *
     161     * 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.
     163     *
     164     * @since 1.2.1
     165     *
     166     * @global PHPMailer $phpmailer
     167     *
     168     * @param string|array $to          Array or comma-separated list of email addresses to send message.
     169     * @param string       $subject     Email subject
     170     * @param string       $message     Message contents
     171     * @param string|array $headers     Optional. Additional headers.
     172     * @param string|array $attachments Optional. Files to attach.
     173     * @return bool Whether the email contents were sent successfully.
     174     */
     175    function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
     176        // Compact the input, apply the filters, and extract them back out
     177
     178        /**
     179         * Filters the wp_mail() arguments.
     180         *
     181         * @since 2.2.0
     182         *
     183         * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
     184         *                    subject, message, headers, and attachments values.
     185         */
     186        $atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
     187
     188        if ( isset( $atts['to'] ) ) {
     189            $to = $atts['to'];
     190        }
     191
     192        if ( ! is_array( $to ) ) {
     193            $to = explode( ',', $to );
     194        }
     195
     196        if ( isset( $atts['subject'] ) ) {
     197            $subject = $atts['subject'];
     198        }
     199
     200        if ( isset( $atts['message'] ) ) {
     201            $message = $atts['message'];
     202        }
     203
     204        if ( isset( $atts['headers'] ) ) {
     205            $headers = $atts['headers'];
     206        }
     207
     208        if ( isset( $atts['attachments'] ) ) {
     209            $attachments = $atts['attachments'];
     210        }
     211
     212        if ( ! is_array( $attachments ) ) {
     213            $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
     214        }
     215        global $phpmailer;
     216
     217        // (Re)create it, if it's gone missing
     218        if ( ! ( $phpmailer instanceof PHPMailer ) ) {
     219            require_once ABSPATH . WPINC . '/class-phpmailer.php';
     220            require_once ABSPATH . WPINC . '/class-smtp.php';
     221            $phpmailer = new PHPMailer( true );
     222        }
     223
     224        // Headers
     225        $cc = $bcc = $reply_to = array();
     226
     227        if ( empty( $headers ) ) {
     228            $headers = array();
    232229        } else {
    233             $tempheaders = $headers;
    234         }
    235         $headers = array();
    236 
    237         // If it's actually got contents
    238         if ( !empty( $tempheaders ) ) {
    239             // Iterate through the raw headers
    240             foreach ( (array) $tempheaders as $header ) {
    241                 if ( strpos($header, ':') === false ) {
    242                     if ( false !== stripos( $header, 'boundary=' ) ) {
    243                         $parts = preg_split('/boundary=/i', trim( $header ) );
    244                         $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
     230            if ( ! is_array( $headers ) ) {
     231                // Explode the headers out, so this function can take both
     232                // string headers and an array of headers.
     233                $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
     234            } else {
     235                $tempheaders = $headers;
     236            }
     237            $headers = array();
     238
     239            // If it's actually got contents
     240            if ( ! empty( $tempheaders ) ) {
     241                // Iterate through the raw headers
     242                foreach ( (array) $tempheaders as $header ) {
     243                    if ( strpos( $header, ':' ) === false ) {
     244                        if ( false !== stripos( $header, 'boundary=' ) ) {
     245                            $parts    = preg_split( '/boundary=/i', trim( $header ) );
     246                            $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
     247                        }
     248                        continue;
    245249                    }
     250                    // Explode them out
     251                    list( $name, $content ) = explode( ':', trim( $header ), 2 );
     252
     253                    // Cleanup crew
     254                    $name    = trim( $name );
     255                    $content = trim( $content );
     256
     257                    switch ( strtolower( $name ) ) {
     258                        // Mainly for legacy -- process a From: header if it's there
     259                        case 'from':
     260                            $bracket_pos = strpos( $content, '<' );
     261                            if ( $bracket_pos !== false ) {
     262                                // Text before the bracketed email is the "From" name.
     263                                if ( $bracket_pos > 0 ) {
     264                                    $from_name = substr( $content, 0, $bracket_pos - 1 );
     265                                    $from_name = str_replace( '"', '', $from_name );
     266                                    $from_name = trim( $from_name );
     267                                }
     268
     269                                $from_email = substr( $content, $bracket_pos + 1 );
     270                                $from_email = str_replace( '>', '', $from_email );
     271                                $from_email = trim( $from_email );
     272
     273                                // Avoid setting an empty $from_email.
     274                            } elseif ( '' !== trim( $content ) ) {
     275                                $from_email = trim( $content );
     276                            }
     277                            break;
     278                        case 'content-type':
     279                            if ( strpos( $content, ';' ) !== false ) {
     280                                list( $type, $charset_content ) = explode( ';', $content );
     281                                $content_type                   = trim( $type );
     282                                if ( false !== stripos( $charset_content, 'charset=' ) ) {
     283                                    $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
     284                                } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
     285                                    $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
     286                                    $charset  = '';
     287                                }
     288
     289                                // Avoid setting an empty $content_type.
     290                            } elseif ( '' !== trim( $content ) ) {
     291                                $content_type = trim( $content );
     292                            }
     293                            break;
     294                        case 'cc':
     295                            $cc = array_merge( (array) $cc, explode( ',', $content ) );
     296                            break;
     297                        case 'bcc':
     298                            $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
     299                            break;
     300                        case 'reply-to':
     301                            $reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
     302                            break;
     303                        default:
     304                            // Add it to our grand headers array
     305                            $headers[ trim( $name ) ] = trim( $content );
     306                            break;
     307                    }
     308                }
     309            }
     310        }
     311
     312        // Empty out the values that may be set
     313        $phpmailer->clearAllRecipients();
     314        $phpmailer->clearAttachments();
     315        $phpmailer->clearCustomHeaders();
     316        $phpmailer->clearReplyTos();
     317
     318        // From email and name
     319        // If we don't have a name from the input headers
     320        if ( ! isset( $from_name ) ) {
     321            $from_name = 'WordPress';
     322        }
     323
     324        /* If we don't have an email from the input headers default to wordpress@$sitename
     325         * Some hosts will block outgoing mail from this address if it doesn't exist but
     326         * there's no easy alternative. Defaulting to admin_email might appear to be another
     327         * option but some hosts may refuse to relay mail from an unknown domain. See
     328         * https://core.trac.wordpress.org/ticket/5007.
     329         */
     330
     331        if ( ! isset( $from_email ) ) {
     332            // Get the site domain and get rid of www.
     333            $sitename = strtolower( $_SERVER['SERVER_NAME'] );
     334            if ( substr( $sitename, 0, 4 ) == 'www.' ) {
     335                $sitename = substr( $sitename, 4 );
     336            }
     337
     338            $from_email = 'wordpress@' . $sitename;
     339        }
     340
     341        /**
     342         * Filters the email address to send from.
     343         *
     344         * @since 2.2.0
     345         *
     346         * @param string $from_email Email address to send from.
     347         */
     348        $from_email = apply_filters( 'wp_mail_from', $from_email );
     349
     350        /**
     351         * Filters the name to associate with the "from" email address.
     352         *
     353         * @since 2.3.0
     354         *
     355         * @param string $from_name Name associated with the "from" email address.
     356         */
     357        $from_name = apply_filters( 'wp_mail_from_name', $from_name );
     358
     359        try {
     360            $phpmailer->setFrom( $from_email, $from_name, false );
     361        } catch ( phpmailerException $e ) {
     362            $mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
     363            $mail_error_data['phpmailer_exception_code'] = $e->getCode();
     364
     365            /** 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 ) );
     367
     368            return false;
     369        }
     370
     371        // Set mail's subject and body
     372        $phpmailer->Subject = $subject;
     373        $phpmailer->Body    = $message;
     374
     375        // Set destination addresses, using appropriate methods for handling addresses
     376        $address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
     377
     378        foreach ( $address_headers as $address_header => $addresses ) {
     379            if ( empty( $addresses ) ) {
     380                continue;
     381            }
     382
     383            foreach ( (array) $addresses as $address ) {
     384                try {
     385                    // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
     386                    $recipient_name = '';
     387
     388                    if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
     389                        if ( count( $matches ) == 3 ) {
     390                            $recipient_name = $matches[1];
     391                            $address        = $matches[2];
     392                        }
     393                    }
     394
     395                    switch ( $address_header ) {
     396                        case 'to':
     397                            $phpmailer->addAddress( $address, $recipient_name );
     398                            break;
     399                        case 'cc':
     400                            $phpmailer->addCc( $address, $recipient_name );
     401                            break;
     402                        case 'bcc':
     403                            $phpmailer->addBcc( $address, $recipient_name );
     404                            break;
     405                        case 'reply_to':
     406                            $phpmailer->addReplyTo( $address, $recipient_name );
     407                            break;
     408                    }
     409                } catch ( phpmailerException $e ) {
    246410                    continue;
    247411                }
    248                 // Explode them out
    249                 list( $name, $content ) = explode( ':', trim( $header ), 2 );
    250 
    251                 // Cleanup crew
    252                 $name    = trim( $name    );
    253                 $content = trim( $content );
    254 
    255                 switch ( strtolower( $name ) ) {
    256                     // Mainly for legacy -- process a From: header if it's there
    257                     case 'from':
    258                         $bracket_pos = strpos( $content, '<' );
    259                         if ( $bracket_pos !== false ) {
    260                             // Text before the bracketed email is the "From" name.
    261                             if ( $bracket_pos > 0 ) {
    262                                 $from_name = substr( $content, 0, $bracket_pos - 1 );
    263                                 $from_name = str_replace( '"', '', $from_name );
    264                                 $from_name = trim( $from_name );
    265                             }
    266 
    267                             $from_email = substr( $content, $bracket_pos + 1 );
    268                             $from_email = str_replace( '>', '', $from_email );
    269                             $from_email = trim( $from_email );
    270 
    271                         // Avoid setting an empty $from_email.
    272                         } elseif ( '' !== trim( $content ) ) {
    273                             $from_email = trim( $content );
    274                         }
    275                         break;
    276                     case 'content-type':
    277                         if ( strpos( $content, ';' ) !== false ) {
    278                             list( $type, $charset_content ) = explode( ';', $content );
    279                             $content_type = trim( $type );
    280                             if ( false !== stripos( $charset_content, 'charset=' ) ) {
    281                                 $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
    282                             } elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
    283                                 $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
    284                                 $charset = '';
    285                             }
    286 
    287                         // Avoid setting an empty $content_type.
    288                         } elseif ( '' !== trim( $content ) ) {
    289                             $content_type = trim( $content );
    290                         }
    291                         break;
    292                     case 'cc':
    293                         $cc = array_merge( (array) $cc, explode( ',', $content ) );
    294                         break;
    295                     case 'bcc':
    296                         $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
    297                         break;
    298                     case 'reply-to':
    299                         $reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
    300                         break;
    301                     default:
    302                         // Add it to our grand headers array
    303                         $headers[trim( $name )] = trim( $content );
    304                         break;
     412            }
     413        }
     414
     415        // Set to use PHP's mail()
     416        $phpmailer->isMail();
     417
     418        // Set Content-Type and charset
     419        // If we don't have a content-type from the input headers
     420        if ( ! isset( $content_type ) ) {
     421            $content_type = 'text/plain';
     422        }
     423
     424        /**
     425         * Filters the wp_mail() content type.
     426         *
     427         * @since 2.3.0
     428         *
     429         * @param string $content_type Default wp_mail() content type.
     430         */
     431        $content_type = apply_filters( 'wp_mail_content_type', $content_type );
     432
     433        $phpmailer->ContentType = $content_type;
     434
     435        // Set whether it's plaintext, depending on $content_type
     436        if ( 'text/html' == $content_type ) {
     437            $phpmailer->isHTML( true );
     438        }
     439
     440        // If we don't have a charset from the input headers
     441        if ( ! isset( $charset ) ) {
     442            $charset = get_bloginfo( 'charset' );
     443        }
     444
     445        // Set the content-type and charset
     446
     447        /**
     448         * Filters the default wp_mail() charset.
     449         *
     450         * @since 2.3.0
     451         *
     452         * @param string $charset Default email charset.
     453         */
     454        $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
     455
     456        // Set custom headers
     457        if ( ! empty( $headers ) ) {
     458            foreach ( (array) $headers as $name => $content ) {
     459                $phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
     460            }
     461
     462            if ( false !== stripos( $content_type, 'multipart' ) && ! empty( $boundary ) ) {
     463                $phpmailer->addCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
     464            }
     465        }
     466
     467        if ( ! empty( $attachments ) ) {
     468            foreach ( $attachments as $attachment ) {
     469                try {
     470                    $phpmailer->addAttachment( $attachment );
     471                } catch ( phpmailerException $e ) {
     472                    continue;
    305473                }
    306474            }
    307475        }
    308     }
    309 
    310     // Empty out the values that may be set
    311     $phpmailer->clearAllRecipients();
    312     $phpmailer->clearAttachments();
    313     $phpmailer->clearCustomHeaders();
    314     $phpmailer->clearReplyTos();
    315 
    316     // From email and name
    317     // If we don't have a name from the input headers
    318     if ( !isset( $from_name ) )
    319         $from_name = 'WordPress';
    320 
    321     /* If we don't have an email from the input headers default to wordpress@$sitename
    322      * Some hosts will block outgoing mail from this address if it doesn't exist but
    323      * there's no easy alternative. Defaulting to admin_email might appear to be another
    324      * option but some hosts may refuse to relay mail from an unknown domain. See
    325      * https://core.trac.wordpress.org/ticket/5007.
    326      */
    327 
    328     if ( !isset( $from_email ) ) {
    329         // Get the site domain and get rid of www.
    330         $sitename = strtolower( $_SERVER['SERVER_NAME'] );
    331         if ( substr( $sitename, 0, 4 ) == 'www.' ) {
    332             $sitename = substr( $sitename, 4 );
    333         }
    334 
    335         $from_email = 'wordpress@' . $sitename;
    336     }
    337 
    338     /**
    339      * Filters the email address to send from.
    340      *
    341      * @since 2.2.0
    342      *
    343      * @param string $from_email Email address to send from.
    344      */
    345     $from_email = apply_filters( 'wp_mail_from', $from_email );
    346 
    347     /**
    348      * Filters the name to associate with the "from" email address.
    349      *
    350      * @since 2.3.0
    351      *
    352      * @param string $from_name Name associated with the "from" email address.
    353      */
    354     $from_name = apply_filters( 'wp_mail_from_name', $from_name );
    355 
    356     try {
    357         $phpmailer->setFrom( $from_email, $from_name, false );
    358     } catch ( phpmailerException $e ) {
    359         $mail_error_data = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
    360         $mail_error_data['phpmailer_exception_code'] = $e->getCode();
    361 
    362         /** This filter is documented in wp-includes/pluggable.php */
    363         do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
    364 
    365         return false;
    366     }
    367 
    368     // Set mail's subject and body
    369     $phpmailer->Subject = $subject;
    370     $phpmailer->Body    = $message;
    371 
    372     // Set destination addresses, using appropriate methods for handling addresses
    373     $address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
    374 
    375     foreach ( $address_headers as $address_header => $addresses ) {
    376         if ( empty( $addresses ) ) {
    377             continue;
    378         }
    379 
    380         foreach ( (array) $addresses as $address ) {
    381             try {
    382                 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
    383                 $recipient_name = '';
    384 
    385                 if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
    386                     if ( count( $matches ) == 3 ) {
    387                         $recipient_name = $matches[1];
    388                         $address        = $matches[2];
    389                     }
    390                 }
    391 
    392                 switch ( $address_header ) {
    393                     case 'to':
    394                         $phpmailer->addAddress( $address, $recipient_name );
    395                         break;
    396                     case 'cc':
    397                         $phpmailer->addCc( $address, $recipient_name );
    398                         break;
    399                     case 'bcc':
    400                         $phpmailer->addBcc( $address, $recipient_name );
    401                         break;
    402                     case 'reply_to':
    403                         $phpmailer->addReplyTo( $address, $recipient_name );
    404                         break;
    405                 }
    406             } catch ( phpmailerException $e ) {
    407                 continue;
    408             }
    409         }
    410     }
    411 
    412     // Set to use PHP's mail()
    413     $phpmailer->isMail();
    414 
    415     // Set Content-Type and charset
    416     // If we don't have a content-type from the input headers
    417     if ( !isset( $content_type ) )
    418         $content_type = 'text/plain';
    419 
    420     /**
    421      * Filters the wp_mail() content type.
    422      *
    423      * @since 2.3.0
    424      *
    425      * @param string $content_type Default wp_mail() content type.
    426      */
    427     $content_type = apply_filters( 'wp_mail_content_type', $content_type );
    428 
    429     $phpmailer->ContentType = $content_type;
    430 
    431     // Set whether it's plaintext, depending on $content_type
    432     if ( 'text/html' == $content_type )
    433         $phpmailer->isHTML( true );
    434 
    435     // If we don't have a charset from the input headers
    436     if ( !isset( $charset ) )
    437         $charset = get_bloginfo( 'charset' );
    438 
    439     // Set the content-type and charset
    440 
    441     /**
    442      * Filters the default wp_mail() charset.
    443      *
    444      * @since 2.3.0
    445      *
    446      * @param string $charset Default email charset.
    447      */
    448     $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
    449 
    450     // Set custom headers
    451     if ( !empty( $headers ) ) {
    452         foreach ( (array) $headers as $name => $content ) {
    453             $phpmailer->addCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
    454         }
    455 
    456         if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
    457             $phpmailer->addCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
    458     }
    459 
    460     if ( !empty( $attachments ) ) {
    461         foreach ( $attachments as $attachment ) {
    462             try {
    463                 $phpmailer->addAttachment($attachment);
    464             } catch ( phpmailerException $e ) {
    465                 continue;
    466             }
    467         }
    468     }
    469 
    470     /**
    471      * Fires after PHPMailer is initialized.
    472      *
    473      * @since 2.2.0
    474      *
    475      * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
    476      */
    477     do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
    478 
    479     // Send!
    480     try {
    481         return $phpmailer->send();
    482     } catch ( phpmailerException $e ) {
    483 
    484         $mail_error_data = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
    485         $mail_error_data['phpmailer_exception_code'] = $e->getCode();
    486 
    487         /**
    488          * Fires after a phpmailerException is caught.
    489          *
    490          * @since 4.4.0
    491          *
    492          * @param WP_Error $error A WP_Error object with the phpmailerException message, and an array
    493          *                        containing the mail recipient, subject, message, headers, and attachments.
    494          */
    495         do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
    496 
    497         return false;
    498     }
    499 }
    500 endif;
    501 
    502 if ( !function_exists('wp_authenticate') ) :
    503 /**
    504  * Authenticate a user, confirming the login credentials are valid.
    505  *
    506  * @since 2.5.0
    507  * @since 4.5.0 `$username` now accepts an email address.
    508  *
    509  * @param string $username User's username or email address.
    510  * @param string $password User's password.
    511  * @return WP_User|WP_Error WP_User object if the credentials are valid,
    512  *                          otherwise WP_Error.
    513  */
    514 function wp_authenticate($username, $password) {
    515     $username = sanitize_user($username);
    516     $password = trim($password);
    517 
    518     /**
    519      * Filters whether a set of user login credentials are valid.
    520      *
    521      * A WP_User object is returned if the credentials authenticate a user.
    522      * WP_Error or null otherwise.
    523      *
    524      * @since 2.8.0
     476
     477        /**
     478         * Fires after PHPMailer is initialized.
     479         *
     480         * @since 2.2.0
     481         *
     482         * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
     483         */
     484        do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
     485
     486        // Send!
     487        try {
     488            return $phpmailer->send();
     489        } catch ( phpmailerException $e ) {
     490
     491            $mail_error_data                             = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
     492            $mail_error_data['phpmailer_exception_code'] = $e->getCode();
     493
     494            /**
     495             * Fires after a phpmailerException is caught.
     496             *
     497             * @since 4.4.0
     498             *
     499             * @param WP_Error $error A WP_Error object with the phpmailerException message, and an array
     500             *                        containing the mail recipient, subject, message, headers, and attachments.
     501             */
     502            do_action( 'wp_mail_failed', new WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_error_data ) );
     503
     504            return false;
     505        }
     506    }
     507endif;
     508
     509if ( ! function_exists( 'wp_authenticate' ) ) :
     510    /**
     511     * Authenticate a user, confirming the login credentials are valid.
     512     *
     513     * @since 2.5.0
    525514     * @since 4.5.0 `$username` now accepts an email address.
    526515     *
    527      * @param null|WP_User|WP_Error $user     WP_User if the user is authenticated.
    528      *                                        WP_Error or null otherwise.
    529      * @param string                $username Username or email address.
    530      * @param string                $password User password
    531      */
    532     $user = apply_filters( 'authenticate', null, $username, $password );
    533 
    534     if ( $user == null ) {
    535         // TODO what should the error message be? (Or would these even happen?)
    536         // Only needed if all authentication handlers fail to return anything.
    537         $user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Invalid username, email address or incorrect password.' ) );
    538     }
    539 
    540     $ignore_codes = array('empty_username', 'empty_password');
    541 
    542     if (is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes) ) {
    543         /**
    544          * Fires after a user login has failed.
    545          *
    546          * @since 2.5.0
    547          * @since 4.5.0 The value of `$username` can now be an email address.
    548          *
    549          * @param string $username Username or email address.
    550          */
    551         do_action( 'wp_login_failed', $username );
    552     }
    553 
    554     return $user;
    555 }
    556 endif;
    557 
    558 if ( !function_exists('wp_logout') ) :
    559 /**
    560  * Log the current user out.
    561  *
    562  * @since 2.5.0
    563  */
    564 function wp_logout() {
    565     wp_destroy_current_session();
    566     wp_clear_auth_cookie();
    567 
    568     /**
    569      * Fires after a user is logged-out.
    570      *
    571      * @since 1.5.0
    572      */
    573     do_action( 'wp_logout' );
    574 }
    575 endif;
    576 
    577 if ( !function_exists('wp_validate_auth_cookie') ) :
    578 /**
    579  * Validates authentication cookie.
    580  *
    581  * The checks include making sure that the authentication cookie is set and
    582  * pulling in the contents (if $cookie is not used).
    583  *
    584  * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
    585  * should be and compares the two.
    586  *
    587  * @since 2.5.0
    588  *
    589  * @global int $login_grace_period
    590  *
    591  * @param string $cookie Optional. If used, will validate contents instead of cookie's
    592  * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
    593  * @return false|int False if invalid cookie, User ID if valid.
    594  */
    595 function wp_validate_auth_cookie($cookie = '', $scheme = '') {
    596     if ( ! $cookie_elements = wp_parse_auth_cookie($cookie, $scheme) ) {
    597         /**
    598          * Fires if an authentication cookie is malformed.
     516     * @param string $username User's username or email address.
     517     * @param string $password User's password.
     518     * @return WP_User|WP_Error WP_User object if the credentials are valid,
     519     *                          otherwise WP_Error.
     520     */
     521    function wp_authenticate( $username, $password ) {
     522        $username = sanitize_user( $username );
     523        $password = trim( $password );
     524
     525        /**
     526         * Filters whether a set of user login credentials are valid.
     527         *
     528         * A WP_User object is returned if the credentials authenticate a user.
     529         * WP_Error or null otherwise.
     530         *
     531         * @since 2.8.0
     532         * @since 4.5.0 `$username` now accepts an email address.
     533         *
     534         * @param null|WP_User|WP_Error $user     WP_User if the user is authenticated.
     535         *                                        WP_Error or null otherwise.
     536         * @param string                $username Username or email address.
     537         * @param string                $password User password
     538         */
     539        $user = apply_filters( 'authenticate', null, $username, $password );
     540
     541        if ( $user == null ) {
     542            // TODO what should the error message be? (Or would these even happen?)
     543            // 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.' ) );
     545        }
     546
     547        $ignore_codes = array( 'empty_username', 'empty_password' );
     548
     549        if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
     550            /**
     551             * Fires after a user login has failed.
     552             *
     553             * @since 2.5.0
     554             * @since 4.5.0 The value of `$username` can now be an email address.
     555             *
     556             * @param string $username Username or email address.
     557             */
     558            do_action( 'wp_login_failed', $username );
     559        }
     560
     561        return $user;
     562    }
     563endif;
     564
     565if ( ! function_exists( 'wp_logout' ) ) :
     566    /**
     567     * Log the current user out.
     568     *
     569     * @since 2.5.0
     570     */
     571    function wp_logout() {
     572        wp_destroy_current_session();
     573        wp_clear_auth_cookie();
     574
     575        /**
     576         * Fires after a user is logged-out.
     577         *
     578         * @since 1.5.0
     579         */
     580        do_action( 'wp_logout' );
     581    }
     582endif;
     583
     584if ( ! function_exists( 'wp_validate_auth_cookie' ) ) :
     585    /**
     586     * Validates authentication cookie.
     587     *
     588     * The checks include making sure that the authentication cookie is set and
     589     * pulling in the contents (if $cookie is not used).
     590     *
     591     * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
     592     * should be and compares the two.
     593     *
     594     * @since 2.5.0
     595     *
     596     * @global int $login_grace_period
     597     *
     598     * @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
     600     * @return false|int False if invalid cookie, User ID if valid.
     601     */
     602    function wp_validate_auth_cookie( $cookie = '', $scheme = '' ) {
     603        if ( ! $cookie_elements = wp_parse_auth_cookie( $cookie, $scheme ) ) {
     604            /**
     605             * Fires if an authentication cookie is malformed.
     606             *
     607             * @since 2.7.0
     608             *
     609             * @param string $cookie Malformed auth cookie.
     610             * @param string $scheme Authentication scheme. Values include 'auth', 'secure_auth',
     611             *                       or 'logged_in'.
     612             */
     613            do_action( 'auth_cookie_malformed', $cookie, $scheme );
     614            return false;
     615        }
     616
     617        $scheme   = $cookie_elements['scheme'];
     618        $username = $cookie_elements['username'];
     619        $hmac     = $cookie_elements['hmac'];
     620        $token    = $cookie_elements['token'];
     621        $expired  = $expiration = $cookie_elements['expiration'];
     622
     623        // Allow a grace period for POST and Ajax requests
     624        if ( wp_doing_ajax() || 'POST' == $_SERVER['REQUEST_METHOD'] ) {
     625            $expired += HOUR_IN_SECONDS;
     626        }
     627
     628        // Quick check to see if an honest cookie has expired
     629        if ( $expired < time() ) {
     630            /**
     631             * Fires once an authentication cookie has expired.
     632             *
     633             * @since 2.7.0
     634             *
     635             * @param array $cookie_elements An array of data for the authentication cookie.
     636             */
     637            do_action( 'auth_cookie_expired', $cookie_elements );
     638            return false;
     639        }
     640
     641        $user = get_user_by( 'login', $username );
     642        if ( ! $user ) {
     643            /**
     644             * Fires if a bad username is entered in the user authentication process.
     645             *
     646             * @since 2.7.0
     647             *
     648             * @param array $cookie_elements An array of data for the authentication cookie.
     649             */
     650            do_action( 'auth_cookie_bad_username', $cookie_elements );
     651            return false;
     652        }
     653
     654        $pass_frag = substr( $user->user_pass, 8, 4 );
     655
     656        $key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
     657
     658        // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
     659        $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
     660        $hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
     661
     662        if ( ! hash_equals( $hash, $hmac ) ) {
     663            /**
     664             * Fires if a bad authentication cookie hash is encountered.
     665             *
     666             * @since 2.7.0
     667             *
     668             * @param array $cookie_elements An array of data for the authentication cookie.
     669             */
     670            do_action( 'auth_cookie_bad_hash', $cookie_elements );
     671            return false;
     672        }
     673
     674        $manager = WP_Session_Tokens::get_instance( $user->ID );
     675        if ( ! $manager->verify( $token ) ) {
     676            do_action( 'auth_cookie_bad_session_token', $cookie_elements );
     677            return false;
     678        }
     679
     680        // Ajax/POST grace period set above
     681        if ( $expiration < time() ) {
     682            $GLOBALS['login_grace_period'] = 1;
     683        }
     684
     685        /**
     686         * Fires once an authentication cookie has been validated.
    599687         *
    600688         * @since 2.7.0
    601689         *
    602          * @param string $cookie Malformed auth cookie.
    603          * @param string $scheme Authentication scheme. Values include 'auth', 'secure_auth',
    604          *                       or 'logged_in'.
    605          */
    606         do_action( 'auth_cookie_malformed', $cookie, $scheme );
    607         return false;
    608     }
    609 
    610     $scheme = $cookie_elements['scheme'];
    611     $username = $cookie_elements['username'];
    612     $hmac = $cookie_elements['hmac'];
    613     $token = $cookie_elements['token'];
    614     $expired = $expiration = $cookie_elements['expiration'];
    615 
    616     // Allow a grace period for POST and Ajax requests
    617     if ( wp_doing_ajax() || 'POST' == $_SERVER['REQUEST_METHOD'] ) {
    618         $expired += HOUR_IN_SECONDS;
    619     }
    620 
    621     // Quick check to see if an honest cookie has expired
    622     if ( $expired < time() ) {
    623         /**
    624          * Fires once an authentication cookie has expired.
    625          *
    626          * @since 2.7.0
    627          *
    628          * @param array $cookie_elements An array of data for the authentication cookie.
    629          */
    630         do_action( 'auth_cookie_expired', $cookie_elements );
    631         return false;
    632     }
    633 
    634     $user = get_user_by('login', $username);
    635     if ( ! $user ) {
    636         /**
    637          * Fires if a bad username is entered in the user authentication process.
    638          *
    639          * @since 2.7.0
    640          *
    641          * @param array $cookie_elements An array of data for the authentication cookie.
    642          */
    643         do_action( 'auth_cookie_bad_username', $cookie_elements );
    644         return false;
    645     }
    646 
    647     $pass_frag = substr($user->user_pass, 8, 4);
    648 
    649     $key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
    650 
    651     // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
    652     $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
    653     $hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
    654 
    655     if ( ! hash_equals( $hash, $hmac ) ) {
    656         /**
    657          * Fires if a bad authentication cookie hash is encountered.
    658          *
    659          * @since 2.7.0
    660          *
    661          * @param array $cookie_elements An array of data for the authentication cookie.
    662          */
    663         do_action( 'auth_cookie_bad_hash', $cookie_elements );
    664         return false;
    665     }
    666 
    667     $manager = WP_Session_Tokens::get_instance( $user->ID );
    668     if ( ! $manager->verify( $token ) ) {
    669         do_action( 'auth_cookie_bad_session_token', $cookie_elements );
    670         return false;
    671     }
    672 
    673     // Ajax/POST grace period set above
    674     if ( $expiration < time() ) {
    675         $GLOBALS['login_grace_period'] = 1;
    676     }
    677 
    678     /**
    679      * Fires once an authentication cookie has been validated.
    680      *
    681      * @since 2.7.0
    682      *
    683      * @param array   $cookie_elements An array of data for the authentication cookie.
    684      * @param WP_User $user            User object.
    685      */
    686     do_action( 'auth_cookie_valid', $cookie_elements, $user );
    687 
    688     return $user->ID;
    689 }
    690 endif;
    691 
    692 if ( !function_exists('wp_generate_auth_cookie') ) :
    693 /**
    694  * Generate authentication cookie contents.
    695  *
    696  * @since 2.5.0
    697  * @since 4.0.0 The `$token` parameter was added.
    698  *
    699  * @param int    $user_id    User ID
    700  * @param int    $expiration The time the cookie expires as a UNIX timestamp.
    701  * @param string $scheme     Optional. The cookie scheme to use: auth, secure_auth, or logged_in
    702  * @param string $token      User's session token to use for this cookie
    703  * @return string Authentication cookie contents. Empty string if user does not exist.
    704  */
    705 function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
    706     $user = get_userdata($user_id);
    707     if ( ! $user ) {
    708         return '';
    709     }
    710 
    711     if ( ! $token ) {
    712         $manager = WP_Session_Tokens::get_instance( $user_id );
    713         $token = $manager->create( $expiration );
    714     }
    715 
    716     $pass_frag = substr($user->user_pass, 8, 4);
    717 
    718     $key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
    719 
    720     // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
    721     $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
    722     $hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );
    723 
    724     $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
    725 
    726     /**
    727      * Filters the authentication cookie.
     690         * @param array   $cookie_elements An array of data for the authentication cookie.
     691         * @param WP_User $user            User object.
     692         */
     693        do_action( 'auth_cookie_valid', $cookie_elements, $user );
     694
     695        return $user->ID;
     696    }
     697endif;
     698
     699if ( ! function_exists( 'wp_generate_auth_cookie' ) ) :
     700    /**
     701     * Generate authentication cookie contents.
    728702     *
    729703     * @since 2.5.0
    730704     * @since 4.0.0 The `$token` parameter was added.
    731705     *
    732      * @param string $cookie     Authentication cookie.
    733      * @param int    $user_id    User ID.
     706     * @param int    $user_id    User ID
    734707     * @param int    $expiration The time the cookie expires as a UNIX timestamp.
    735      * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
    736      * @param string $token      User's session token used.
    737      */
    738     return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
    739 }
    740 endif;
    741 
    742 if ( !function_exists('wp_parse_auth_cookie') ) :
    743 /**
    744  * Parse a cookie into its components
    745  *
    746  * @since 2.7.0
    747  *
    748  * @param string $cookie
    749  * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
    750  * @return array|false Authentication cookie components
    751  */
    752 function wp_parse_auth_cookie($cookie = '', $scheme = '') {
    753     if ( empty($cookie) ) {
    754         switch ($scheme){
    755             case 'auth':
    756                 $cookie_name = AUTH_COOKIE;
    757                 break;
    758             case 'secure_auth':
    759                 $cookie_name = SECURE_AUTH_COOKIE;
    760                 break;
    761             case "logged_in":
    762                 $cookie_name = LOGGED_IN_COOKIE;
    763                 break;
    764             default:
    765                 if ( is_ssl() ) {
     708     * @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
     710     * @return string Authentication cookie contents. Empty string if user does not exist.
     711     */
     712    function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
     713        $user = get_userdata( $user_id );
     714        if ( ! $user ) {
     715            return '';
     716        }
     717
     718        if ( ! $token ) {
     719            $manager = WP_Session_Tokens::get_instance( $user_id );
     720            $token   = $manager->create( $expiration );
     721        }
     722
     723        $pass_frag = substr( $user->user_pass, 8, 4 );
     724
     725        $key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
     726
     727        // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
     728        $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
     729        $hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );
     730
     731        $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
     732
     733        /**
     734         * Filters the authentication cookie.
     735         *
     736         * @since 2.5.0
     737         * @since 4.0.0 The `$token` parameter was added.
     738         *
     739         * @param string $cookie     Authentication cookie.
     740         * @param int    $user_id    User ID.
     741         * @param int    $expiration The time the cookie expires as a UNIX timestamp.
     742         * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
     743         * @param string $token      User's session token used.
     744         */
     745        return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
     746    }
     747endif;
     748
     749if ( ! function_exists( 'wp_parse_auth_cookie' ) ) :
     750    /**
     751     * Parse a cookie into its components
     752     *
     753     * @since 2.7.0
     754     *
     755     * @param string $cookie
     756     * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
     757     * @return array|false Authentication cookie components
     758     */
     759    function wp_parse_auth_cookie( $cookie = '', $scheme = '' ) {
     760        if ( empty( $cookie ) ) {
     761            switch ( $scheme ) {
     762                case 'auth':
     763                    $cookie_name = AUTH_COOKIE;
     764                    break;
     765                case 'secure_auth':
    766766                    $cookie_name = SECURE_AUTH_COOKIE;
    767                     $scheme = 'secure_auth';
    768                 } else {
    769                     $cookie_name = AUTH_COOKIE;
    770                     $scheme = 'auth';
    771                 }
    772         }
    773 
    774         if ( empty($_COOKIE[$cookie_name]) )
     767                    break;
     768                case 'logged_in':
     769                    $cookie_name = LOGGED_IN_COOKIE;
     770                    break;
     771                default:
     772                    if ( is_ssl() ) {
     773                        $cookie_name = SECURE_AUTH_COOKIE;
     774                        $scheme      = 'secure_auth';
     775                    } else {
     776                        $cookie_name = AUTH_COOKIE;
     777                        $scheme      = 'auth';
     778                    }
     779            }
     780
     781            if ( empty( $_COOKIE[ $cookie_name ] ) ) {
     782                return false;
     783            }
     784            $cookie = $_COOKIE[ $cookie_name ];
     785        }
     786
     787        $cookie_elements = explode( '|', $cookie );
     788        if ( count( $cookie_elements ) !== 4 ) {
    775789            return false;
    776         $cookie = $_COOKIE[$cookie_name];
    777     }
    778 
    779     $cookie_elements = explode('|', $cookie);
    780     if ( count( $cookie_elements ) !== 4 ) {
    781         return false;
    782     }
    783 
    784     list( $username, $expiration, $token, $hmac ) = $cookie_elements;
    785 
    786     return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
    787 }
    788 endif;
    789 
    790 if ( !function_exists('wp_set_auth_cookie') ) :
    791 /**
    792  * Log in a user by setting authentication cookies.
    793  *
    794  * The $remember parameter increases the time that the cookie will be kept. The
    795  * default the cookie is kept without remembering is two days. When $remember is
    796  * set, the cookies will be kept for 14 days or two weeks.
    797  *
    798  * @since 2.5.0
    799  * @since 4.3.0 Added the `$token` parameter.
    800  *
    801  * @param int    $user_id  User ID
    802  * @param bool   $remember Whether to remember the user
    803  * @param mixed  $secure   Whether the admin cookies should only be sent over HTTPS.
    804  *                         Default is_ssl().
    805  * @param string $token    Optional. User's session token to use for this cookie.
    806  */
    807 function wp_set_auth_cookie( $user_id, $remember = false, $secure = '', $token = '' ) {
    808     if ( $remember ) {
    809         /**
    810          * Filters the duration of the authentication cookie expiration period.
    811          *
    812          * @since 2.8.0
    813          *
    814          * @param int  $length   Duration of the expiration period in seconds.
    815          * @param int  $user_id  User ID.
    816          * @param bool $remember Whether to remember the user login. Default false.
    817          */
    818         $expiration = time() + apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
    819 
    820         /*
    821          * Ensure the browser will continue to send the cookie after the expiration time is reached.
    822          * Needed for the login grace period in wp_validate_auth_cookie().
    823          */
    824         $expire = $expiration + ( 12 * HOUR_IN_SECONDS );
    825     } else {
     790        }
     791
     792        list( $username, $expiration, $token, $hmac ) = $cookie_elements;
     793
     794        return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
     795    }
     796endif;
     797
     798if ( ! function_exists( 'wp_set_auth_cookie' ) ) :
     799    /**
     800     * Log in a user by setting authentication cookies.
     801     *
     802     * 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
     804     * set, the cookies will be kept for 14 days or two weeks.
     805     *
     806     * @since 2.5.0
     807     * @since 4.3.0 Added the `$token` parameter.
     808     *
     809     * @param int    $user_id  User ID
     810     * @param bool   $remember Whether to remember the user
     811     * @param mixed  $secure   Whether the admin cookies should only be sent over HTTPS.
     812     *                         Default is_ssl().
     813     * @param string $token    Optional. User's session token to use for this cookie.
     814     */
     815    function wp_set_auth_cookie( $user_id, $remember = false, $secure = '', $token = '' ) {
     816        if ( $remember ) {
     817            /**
     818             * Filters the duration of the authentication cookie expiration period.
     819             *
     820             * @since 2.8.0
     821             *
     822             * @param int  $length   Duration of the expiration period in seconds.
     823             * @param int  $user_id  User ID.
     824             * @param bool $remember Whether to remember the user login. Default false.
     825             */
     826            $expiration = time() + apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
     827
     828            /*
     829             * Ensure the browser will continue to send the cookie after the expiration time is reached.
     830             * Needed for the login grace period in wp_validate_auth_cookie().
     831             */
     832            $expire = $expiration + ( 12 * HOUR_IN_SECONDS );
     833        } else {
     834            /** This filter is documented in wp-includes/pluggable.php */
     835            $expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user_id, $remember );
     836            $expire     = 0;
     837        }
     838
     839        if ( '' === $secure ) {
     840            $secure = is_ssl();
     841        }
     842
     843        // Front-end cookie is secure when the auth cookie is secure and the site's home URL is forced HTTPS.
     844        $secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
     845
     846        /**
     847         * Filters whether the connection is secure.
     848         *
     849         * @since 3.1.0
     850         *
     851         * @param bool $secure  Whether the connection is secure.
     852         * @param int  $user_id User ID.
     853         */
     854        $secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
     855
     856        /**
     857         * Filters whether to use a secure cookie when logged-in.
     858         *
     859         * @since 3.1.0
     860         *
     861         * @param bool $secure_logged_in_cookie Whether to use a secure cookie when logged-in.
     862         * @param int  $user_id                 User ID.
     863         * @param bool $secure                  Whether the connection is secure.
     864         */
     865        $secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
     866
     867        if ( $secure ) {
     868            $auth_cookie_name = SECURE_AUTH_COOKIE;
     869            $scheme           = 'secure_auth';
     870        } else {
     871            $auth_cookie_name = AUTH_COOKIE;
     872            $scheme           = 'auth';
     873        }
     874
     875        if ( '' === $token ) {
     876            $manager = WP_Session_Tokens::get_instance( $user_id );
     877            $token   = $manager->create( $expiration );
     878        }
     879
     880        $auth_cookie      = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
     881        $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
     882
     883        /**
     884         * Fires immediately before the authentication cookie is set.
     885         *
     886         * @since 2.5.0
     887         * @since 4.9.0 The `$token` parameter was added.
     888         *
     889         * @param string $auth_cookie Authentication cookie.
     890         * @param int    $expire      The time the login grace period expires as a UNIX timestamp.
     891         *                            Default is 12 hours past the cookie's expiration time.
     892         * @param int    $expiration  The time when the authentication cookie expires as a UNIX timestamp.
     893         *                            Default is 14 days from now.
     894         * @param int    $user_id     User ID.
     895         * @param string $scheme      Authentication scheme. Values include 'auth', 'secure_auth', or 'logged_in'.
     896         * @param string $token       User's session token to use for this cookie.
     897         */
     898        do_action( 'set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme, $token );
     899
     900        /**
     901         * Fires immediately before the logged-in authentication cookie is set.
     902         *
     903         * @since 2.6.0
     904         * @since 4.9.0 The `$token` parameter was added.
     905         *
     906         * @param string $logged_in_cookie The logged-in cookie.
     907         * @param int    $expire           The time the login grace period expires as a UNIX timestamp.
     908         *                                 Default is 12 hours past the cookie's expiration time.
     909         * @param int    $expiration       The time when the logged-in authentication cookie expires as a UNIX timestamp.
     910         *                                 Default is 14 days from now.
     911         * @param int    $user_id          User ID.
     912         * @param string $scheme           Authentication scheme. Default 'logged_in'.
     913         * @param string $token            User's session token to use for this cookie.
     914         */
     915        do_action( 'set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in', $token );
     916
     917        /**
     918         * Allows preventing auth cookies from actually being sent to the client.
     919         *
     920         * @since 4.7.4
     921         *
     922         * @param bool $send Whether to send auth cookies to the client.
     923         */
     924        if ( ! apply_filters( 'send_auth_cookies', true ) ) {
     925            return;
     926        }
     927
     928        setcookie( $auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true );
     929        setcookie( $auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true );
     930        setcookie( LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true );
     931        if ( COOKIEPATH != SITECOOKIEPATH ) {
     932            setcookie( LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true );
     933        }
     934    }
     935endif;
     936
     937if ( ! function_exists( 'wp_clear_auth_cookie' ) ) :
     938    /**
     939     * Removes all of the cookies associated with authentication.
     940     *
     941     * @since 2.5.0
     942     */
     943    function wp_clear_auth_cookie() {
     944        /**
     945         * Fires just before the authentication cookies are cleared.
     946         *
     947         * @since 2.7.0
     948         */
     949        do_action( 'clear_auth_cookie' );
     950
    826951        /** This filter is documented in wp-includes/pluggable.php */
    827         $expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user_id, $remember );
    828         $expire = 0;
    829     }
    830 
    831     if ( '' === $secure ) {
    832         $secure = is_ssl();
    833     }
    834 
    835     // Front-end cookie is secure when the auth cookie is secure and the site's home URL is forced HTTPS.
    836     $secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
    837 
    838     /**
    839      * Filters whether the connection is secure.
    840      *
    841      * @since 3.1.0
    842      *
    843      * @param bool $secure  Whether the connection is secure.
    844      * @param int  $user_id User ID.
    845      */
    846     $secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
    847 
    848     /**
    849      * Filters whether to use a secure cookie when logged-in.
    850      *
    851      * @since 3.1.0
    852      *
    853      * @param bool $secure_logged_in_cookie Whether to use a secure cookie when logged-in.
    854      * @param int  $user_id                 User ID.
    855      * @param bool $secure                  Whether the connection is secure.
    856      */
    857     $secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
    858 
    859     if ( $secure ) {
    860         $auth_cookie_name = SECURE_AUTH_COOKIE;
    861         $scheme = 'secure_auth';
    862     } else {
    863         $auth_cookie_name = AUTH_COOKIE;
    864         $scheme = 'auth';
    865     }
    866 
    867     if ( '' === $token ) {
    868         $manager = WP_Session_Tokens::get_instance( $user_id );
    869         $token   = $manager->create( $expiration );
    870     }
    871 
    872     $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
    873     $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
    874 
    875     /**
    876      * Fires immediately before the authentication cookie is set.
    877      *
    878      * @since 2.5.0
    879      * @since 4.9.0 The `$token` parameter was added.
    880      *
    881      * @param string $auth_cookie Authentication cookie.
    882      * @param int    $expire      The time the login grace period expires as a UNIX timestamp.
    883      *                            Default is 12 hours past the cookie's expiration time.
    884      * @param int    $expiration  The time when the authentication cookie expires as a UNIX timestamp.
    885      *                            Default is 14 days from now.
    886      * @param int    $user_id     User ID.
    887      * @param string $scheme      Authentication scheme. Values include 'auth', 'secure_auth', or 'logged_in'.
    888      * @param string $token       User's session token to use for this cookie.
    889      */
    890     do_action( 'set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme, $token );
    891 
    892     /**
    893      * Fires immediately before the logged-in authentication cookie is set.
    894      *
    895      * @since 2.6.0
    896      * @since 4.9.0 The `$token` parameter was added.
    897      *
    898      * @param string $logged_in_cookie The logged-in cookie.
    899      * @param int    $expire           The time the login grace period expires as a UNIX timestamp.
    900      *                                 Default is 12 hours past the cookie's expiration time.
    901      * @param int    $expiration       The time when the logged-in authentication cookie expires as a UNIX timestamp.
    902      *                                 Default is 14 days from now.
    903      * @param int    $user_id          User ID.
    904      * @param string $scheme           Authentication scheme. Default 'logged_in'.
    905      * @param string $token            User's session token to use for this cookie.
    906      */
    907     do_action( 'set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in', $token );
    908 
    909     /**
    910      * Allows preventing auth cookies from actually being sent to the client.
    911      *
    912      * @since 4.7.4
    913      *
    914      * @param bool $send Whether to send auth cookies to the client.
    915      */
    916     if ( ! apply_filters( 'send_auth_cookies', true ) ) {
    917         return;
    918     }
    919 
    920     setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
    921     setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
    922     setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
    923     if ( COOKIEPATH != SITECOOKIEPATH )
    924         setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
    925 }
    926 endif;
    927 
    928 if ( !function_exists('wp_clear_auth_cookie') ) :
    929 /**
    930  * Removes all of the cookies associated with authentication.
    931  *
    932  * @since 2.5.0
    933  */
    934 function wp_clear_auth_cookie() {
    935     /**
    936      * Fires just before the authentication cookies are cleared.
    937      *
    938      * @since 2.7.0
    939      */
    940     do_action( 'clear_auth_cookie' );
    941 
    942     /** This filter is documented in wp-includes/pluggable.php */
    943     if ( ! apply_filters( 'send_auth_cookies', true ) ) {
    944         return;
    945     }
    946 
    947     // Auth cookies
    948     setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
    949     setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
    950     setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
    951     setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
    952     setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,          COOKIE_DOMAIN );
    953     setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH,      COOKIE_DOMAIN );
    954 
    955     // Settings cookies
    956     setcookie( 'wp-settings-' . get_current_user_id(),      ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
    957     setcookie( 'wp-settings-time-' . get_current_user_id(), ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH );
    958 
    959     // Old cookies
    960     setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
    961     setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
    962     setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
    963     setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
    964 
    965     // Even older cookies
    966     setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
    967     setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
    968     setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
    969     setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
    970 }
    971 endif;
    972 
    973 if ( !function_exists('is_user_logged_in') ) :
    974 /**
    975  * Checks if the current visitor is a logged in user.
    976  *
    977  * @since 2.0.0
    978  *
    979  * @return bool True if user is logged in, false if not logged in.
    980  */
    981 function is_user_logged_in() {
    982     $user = wp_get_current_user();
    983 
    984     return $user->exists();
    985 }
    986 endif;
    987 
    988 if ( !function_exists('auth_redirect') ) :
    989 /**
    990  * Checks if a user is logged in, if not it redirects them to the login page.
    991  *
    992  * @since 1.5.0
    993  */
    994 function auth_redirect() {
    995     // Checks if a user is logged in, if not redirects them to the login page
    996 
    997     $secure = ( is_ssl() || force_ssl_admin() );
    998 
    999     /**
    1000      * Filters whether to use a secure authentication redirect.
    1001      *
    1002      * @since 3.1.0
    1003      *
    1004      * @param bool $secure Whether to use a secure authentication redirect. Default false.
    1005      */
    1006     $secure = apply_filters( 'secure_auth_redirect', $secure );
    1007 
    1008     // If https is required and request is http, redirect
    1009     if ( $secure && !is_ssl() && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
    1010         if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
    1011             wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
    1012             exit();
    1013         } else {
    1014             wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
    1015             exit();
    1016         }
    1017     }
    1018 
    1019     /**
    1020      * Filters the authentication redirect scheme.
    1021      *
    1022      * @since 2.9.0
    1023      *
    1024      * @param string $scheme Authentication redirect scheme. Default empty.
    1025      */
    1026     $scheme = apply_filters( 'auth_redirect_scheme', '' );
    1027 
    1028     if ( $user_id = wp_validate_auth_cookie( '',  $scheme) ) {
    1029         /**
    1030          * Fires before the authentication redirect.
    1031          *
    1032          * @since 2.8.0
    1033          *
    1034          * @param int $user_id User ID.
    1035          */
    1036         do_action( 'auth_redirect', $user_id );
    1037 
    1038         // If the user wants ssl but the session is not ssl, redirect.
    1039         if ( !$secure && get_user_option('use_ssl', $user_id) && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
     952        if ( ! apply_filters( 'send_auth_cookies', true ) ) {
     953            return;
     954        }
     955
     956        // Auth cookies
     957        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 );
     959        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 );
     961        setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
     962        setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
     963
     964        // Settings cookies
     965        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 );
     967
     968        // Old cookies
     969        setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
     970        setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
     971        setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
     972        setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
     973
     974        // Even older cookies
     975        setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
     976        setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
     977        setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
     978        setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
     979    }
     980endif;
     981
     982if ( ! function_exists( 'is_user_logged_in' ) ) :
     983    /**
     984     * Checks if the current visitor is a logged in user.
     985     *
     986     * @since 2.0.0
     987     *
     988     * @return bool True if user is logged in, false if not logged in.
     989     */
     990    function is_user_logged_in() {
     991        $user = wp_get_current_user();
     992
     993        return $user->exists();
     994    }
     995endif;
     996
     997if ( ! function_exists( 'auth_redirect' ) ) :
     998    /**
     999     * Checks if a user is logged in, if not it redirects them to the login page.
     1000     *
     1001     * @since 1.5.0
     1002     */
     1003    function auth_redirect() {
     1004        // Checks if a user is logged in, if not redirects them to the login page
     1005
     1006        $secure = ( is_ssl() || force_ssl_admin() );
     1007
     1008        /**
     1009         * Filters whether to use a secure authentication redirect.
     1010         *
     1011         * @since 3.1.0
     1012         *
     1013         * @param bool $secure Whether to use a secure authentication redirect. Default false.
     1014         */
     1015        $secure = apply_filters( 'secure_auth_redirect', $secure );
     1016
     1017        // If https is required and request is http, redirect
     1018        if ( $secure && ! is_ssl() && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
    10401019            if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
    10411020                wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
     
    10471026        }
    10481027
    1049         return;  // The cookie is good so we're done
    1050     }
    1051 
    1052     // The cookie is no good so force login
    1053     nocache_headers();
    1054 
    1055     $redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
    1056 
    1057     $login_url = wp_login_url($redirect, true);
    1058 
    1059     wp_redirect($login_url);
    1060     exit();
    1061 }
    1062 endif;
    1063 
    1064 if ( !function_exists('check_admin_referer') ) :
    1065 /**
    1066  * Makes sure that a user was referred from another admin page.
    1067  *
    1068  * To avoid security exploits.
    1069  *
    1070  * @since 1.2.0
    1071  *
    1072  * @param int|string $action    Action nonce.
    1073  * @param string     $query_arg Optional. Key to check for nonce in `$_REQUEST` (since 2.5).
    1074  *                              Default '_wpnonce'.
    1075  * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
    1076  *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
    1077  */
    1078 function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
    1079     if ( -1 == $action )
    1080         _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2.0' );
    1081 
    1082     $adminurl = strtolower(admin_url());
    1083     $referer = strtolower(wp_get_referer());
    1084     $result = isset($_REQUEST[$query_arg]) ? wp_verify_nonce($_REQUEST[$query_arg], $action) : false;
    1085 
    1086     /**
    1087      * Fires once the admin request has been validated or not.
     1028        /**
     1029         * Filters the authentication redirect scheme.
     1030         *
     1031         * @since 2.9.0
     1032         *
     1033         * @param string $scheme Authentication redirect scheme. Default empty.
     1034         */
     1035        $scheme = apply_filters( 'auth_redirect_scheme', '' );
     1036
     1037        if ( $user_id = wp_validate_auth_cookie( '', $scheme ) ) {
     1038            /**
     1039             * Fires before the authentication redirect.
     1040             *
     1041             * @since 2.8.0
     1042             *
     1043             * @param int $user_id User ID.
     1044             */
     1045            do_action( 'auth_redirect', $user_id );
     1046
     1047            // If the user wants ssl but the session is not ssl, redirect.
     1048            if ( ! $secure && get_user_option( 'use_ssl', $user_id ) && false !== strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) ) {
     1049                if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
     1050                    wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
     1051                    exit();
     1052                } else {
     1053                    wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
     1054                    exit();
     1055                }
     1056            }
     1057
     1058            return;  // The cookie is good so we're done
     1059        }
     1060
     1061        // The cookie is no good so force login
     1062        nocache_headers();
     1063
     1064        $redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
     1065
     1066        $login_url = wp_login_url( $redirect, true );
     1067
     1068        wp_redirect( $login_url );
     1069        exit();
     1070    }
     1071endif;
     1072
     1073if ( ! function_exists( 'check_admin_referer' ) ) :
     1074    /**
     1075     * Makes sure that a user was referred from another admin page.
     1076     *
     1077     * To avoid security exploits.
     1078     *
     1079     * @since 1.2.0
     1080     *
     1081     * @param int|string $action    Action nonce.
     1082     * @param string     $query_arg Optional. Key to check for nonce in `$_REQUEST` (since 2.5).
     1083     *                              Default '_wpnonce'.
     1084     * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
     1085     *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
     1086     */
     1087    function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
     1088        if ( -1 == $action ) {
     1089            _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2.0' );
     1090        }
     1091
     1092        $adminurl = strtolower( admin_url() );
     1093        $referer  = strtolower( wp_get_referer() );
     1094        $result   = isset( $_REQUEST[ $query_arg ] ) ? wp_verify_nonce( $_REQUEST[ $query_arg ], $action ) : false;
     1095
     1096        /**
     1097         * Fires once the admin request has been validated or not.
     1098         *
     1099         * @since 1.5.1
     1100         *
     1101         * @param string    $action The nonce action.
     1102         * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
     1103         *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
     1104         */
     1105        do_action( 'check_admin_referer', $action, $result );
     1106
     1107        if ( ! $result && ! ( -1 == $action && strpos( $referer, $adminurl ) === 0 ) ) {
     1108            wp_nonce_ays( $action );
     1109            die();
     1110        }
     1111
     1112        return $result;
     1113    }
     1114endif;
     1115
     1116if ( ! function_exists( 'check_ajax_referer' ) ) :
     1117    /**
     1118     * Verifies the Ajax request to prevent processing requests external of the blog.
     1119     *
     1120     * @since 2.0.3
     1121     *
     1122     * @param int|string   $action    Action nonce.
     1123     * @param false|string $query_arg Optional. Key to check for the nonce in `$_REQUEST` (since 2.5). If false,
     1124     *                                `$_REQUEST` values will be evaluated for '_ajax_nonce', and '_wpnonce'
     1125     *                                (in that order). Default false.
     1126     * @param bool         $die       Optional. Whether to die early when the nonce cannot be verified.
     1127     *                                Default true.
     1128     * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
     1129     *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
     1130     */
     1131    function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
     1132        if ( -1 == $action ) {
     1133            _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '4.7' );
     1134        }
     1135
     1136        $nonce = '';
     1137
     1138        if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) ) {
     1139            $nonce = $_REQUEST[ $query_arg ];
     1140        } elseif ( isset( $_REQUEST['_ajax_nonce'] ) ) {
     1141            $nonce = $_REQUEST['_ajax_nonce'];
     1142        } elseif ( isset( $_REQUEST['_wpnonce'] ) ) {
     1143            $nonce = $_REQUEST['_wpnonce'];
     1144        }
     1145
     1146        $result = wp_verify_nonce( $nonce, $action );
     1147
     1148        /**
     1149         * Fires once the Ajax request has been validated or not.
     1150         *
     1151         * @since 2.1.0
     1152         *
     1153         * @param string    $action The Ajax nonce action.
     1154         * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
     1155         *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
     1156         */
     1157        do_action( 'check_ajax_referer', $action, $result );
     1158
     1159        if ( $die && false === $result ) {
     1160            if ( wp_doing_ajax() ) {
     1161                wp_die( -1, 403 );
     1162            } else {
     1163                die( '-1' );
     1164            }
     1165        }
     1166
     1167        return $result;
     1168    }
     1169endif;
     1170
     1171if ( ! function_exists( 'wp_redirect' ) ) :
     1172    /**
     1173     * Redirects to another page.
     1174     *
     1175     * Note: wp_redirect() does not exit automatically, and should almost always be
     1176     * followed by a call to `exit;`:
     1177     *
     1178     *     wp_redirect( $url );
     1179     *     exit;
     1180     *
     1181     * Exiting can also be selectively manipulated by using wp_redirect() as a conditional
     1182     * in conjunction with the {@see 'wp_redirect'} and {@see 'wp_redirect_location'} filters:
     1183     *
     1184     *     if ( wp_redirect( $url ) ) {
     1185     *         exit;
     1186     *     }
    10881187     *
    10891188     * @since 1.5.1
    10901189     *
    1091      * @param string    $action The nonce action.
    1092      * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
    1093      *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
    1094      */
    1095     do_action( 'check_admin_referer', $action, $result );
    1096 
    1097     if ( ! $result && ! ( -1 == $action && strpos( $referer, $adminurl ) === 0 ) ) {
    1098         wp_nonce_ays( $action );
    1099         die();
    1100     }
    1101 
    1102     return $result;
    1103 }
    1104 endif;
    1105 
    1106 if ( !function_exists('check_ajax_referer') ) :
    1107 /**
    1108  * Verifies the Ajax request to prevent processing requests external of the blog.
    1109  *
    1110  * @since 2.0.3
    1111  *
    1112  * @param int|string   $action    Action nonce.
    1113  * @param false|string $query_arg Optional. Key to check for the nonce in `$_REQUEST` (since 2.5). If false,
    1114  *                                `$_REQUEST` values will be evaluated for '_ajax_nonce', and '_wpnonce'
    1115  *                                (in that order). Default false.
    1116  * @param bool         $die       Optional. Whether to die early when the nonce cannot be verified.
    1117  *                                Default true.
    1118  * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
    1119  *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
    1120  */
    1121 function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
    1122     if ( -1 == $action ) {
    1123         _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '4.7' );
    1124     }
    1125 
    1126     $nonce = '';
    1127 
    1128     if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) )
    1129         $nonce = $_REQUEST[ $query_arg ];
    1130     elseif ( isset( $_REQUEST['_ajax_nonce'] ) )
    1131         $nonce = $_REQUEST['_ajax_nonce'];
    1132     elseif ( isset( $_REQUEST['_wpnonce'] ) )
    1133         $nonce = $_REQUEST['_wpnonce'];
    1134 
    1135     $result = wp_verify_nonce( $nonce, $action );
    1136 
    1137     /**
    1138      * Fires once the Ajax request has been validated or not.
    1139      *
    1140      * @since 2.1.0
    1141      *
    1142      * @param string    $action The Ajax nonce action.
    1143      * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
    1144      *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
    1145      */
    1146     do_action( 'check_ajax_referer', $action, $result );
    1147 
    1148     if ( $die && false === $result ) {
    1149         if ( wp_doing_ajax() ) {
    1150             wp_die( -1, 403 );
    1151         } else {
    1152             die( '-1' );
    1153         }
    1154     }
    1155 
    1156     return $result;
    1157 }
    1158 endif;
    1159 
    1160 if ( !function_exists('wp_redirect') ) :
    1161 /**
    1162  * Redirects to another page.
    1163  *
    1164  * Note: wp_redirect() does not exit automatically, and should almost always be
    1165  * followed by a call to `exit;`:
    1166  *
    1167  *     wp_redirect( $url );
    1168  *     exit;
    1169  *
    1170  * Exiting can also be selectively manipulated by using wp_redirect() as a conditional
    1171  * in conjunction with the {@see 'wp_redirect'} and {@see 'wp_redirect_location'} filters:
    1172  *
    1173  *     if ( wp_redirect( $url ) ) {
    1174  *         exit;
    1175  *     }
    1176  *
    1177  * @since 1.5.1
    1178  *
    1179  * @global bool $is_IIS
    1180  *
    1181  * @param string $location The path or URL to redirect to.
    1182  * @param int    $status   Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
    1183  * @return bool False if the redirect was cancelled, true otherwise.
    1184  */
    1185 function wp_redirect($location, $status = 302) {
    1186     global $is_IIS;
    1187 
    1188     /**
    1189      * Filters the redirect location.
    1190      *
    1191      * @since 2.1.0
     1190     * @global bool $is_IIS
    11921191     *
    11931192     * @param string $location The path or URL to redirect to.
    1194      * @param int    $status   The HTTP response status code to use.
    1195      */
    1196     $location = apply_filters( 'wp_redirect', $location, $status );
    1197 
    1198     /**
    1199      * Filters the redirect HTTP response status code to use.
     1193     * @param int    $status   Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
     1194     * @return bool False if the redirect was cancelled, true otherwise.
     1195     */
     1196    function wp_redirect( $location, $status = 302 ) {
     1197        global $is_IIS;
     1198
     1199        /**
     1200         * Filters the redirect location.
     1201         *
     1202         * @since 2.1.0
     1203         *
     1204         * @param string $location The path or URL to redirect to.
     1205         * @param int    $status   The HTTP response status code to use.
     1206         */
     1207        $location = apply_filters( 'wp_redirect', $location, $status );
     1208
     1209        /**
     1210         * Filters the redirect HTTP response status code to use.
     1211         *
     1212         * @since 2.3.0
     1213         *
     1214         * @param int    $status   The HTTP response status code to use.
     1215         * @param string $location The path or URL to redirect to.
     1216         */
     1217        $status = apply_filters( 'wp_redirect_status', $status, $location );
     1218
     1219        if ( ! $location ) {
     1220            return false;
     1221        }
     1222
     1223        $location = wp_sanitize_redirect( $location );
     1224
     1225        if ( ! $is_IIS && PHP_SAPI != 'cgi-fcgi' ) {
     1226            status_header( $status ); // This causes problems on IIS and some FastCGI setups
     1227        }
     1228
     1229        header( "Location: $location", true, $status );
     1230
     1231        return true;
     1232    }
     1233endif;
     1234
     1235if ( ! function_exists( 'wp_sanitize_redirect' ) ) :
     1236    /**
     1237     * Sanitizes a URL for use in a redirect.
    12001238     *
    12011239     * @since 2.3.0
    12021240     *
    1203      * @param int    $status   The HTTP response status code to use.
    1204      * @param string $location The path or URL to redirect to.
    1205      */
    1206     $status = apply_filters( 'wp_redirect_status', $status, $location );
    1207 
    1208     if ( ! $location )
    1209         return false;
    1210 
    1211     $location = wp_sanitize_redirect($location);
    1212 
    1213     if ( !$is_IIS && PHP_SAPI != 'cgi-fcgi' )
    1214         status_header($status); // This causes problems on IIS and some FastCGI setups
    1215 
    1216     header("Location: $location", true, $status);
    1217 
    1218     return true;
    1219 }
    1220 endif;
    1221 
    1222 if ( !function_exists('wp_sanitize_redirect') ) :
    1223 /**
    1224  * Sanitizes a URL for use in a redirect.
    1225  *
    1226  * @since 2.3.0
    1227  *
    1228  * @param string $location The path to redirect to.
    1229  * @return string Redirect-sanitized URL.
    1230  **/
    1231 function wp_sanitize_redirect($location) {
    1232     $regex = '/
     1241     * @param string $location The path to redirect to.
     1242     * @return string Redirect-sanitized URL.
     1243     */
     1244    function wp_sanitize_redirect( $location ) {
     1245        $regex    = '/
    12331246        (
    12341247            (?: [\xC2-\xDF][\x80-\xBF]        # double-byte sequences   110xxxxx 10xxxxxx
     
    12421255        ){1,40}                              # ...one or more times
    12431256        )/x';
    1244     $location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
    1245     $location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location);
    1246     $location = wp_kses_no_null($location);
    1247 
    1248     // remove %0d and %0a from location
    1249     $strip = array('%0d', '%0a', '%0D', '%0A');
    1250     return _deep_replace( $strip, $location );
    1251 }
    1252 
    1253 /**
    1254  * URL encode UTF-8 characters in a URL.
    1255  *
    1256  * @ignore
    1257  * @since 4.2.0
    1258  * @access private
    1259  *
    1260  * @see wp_sanitize_redirect()
    1261  *
    1262  * @param array $matches RegEx matches against the redirect location.
    1263  * @return string URL-encoded version of the first RegEx match.
    1264  */
    1265 function _wp_sanitize_utf8_in_redirect( $matches ) {
    1266     return urlencode( $matches[0] );
    1267 }
    1268 endif;
    1269 
    1270 if ( !function_exists('wp_safe_redirect') ) :
    1271 /**
    1272  * Performs a safe (local) redirect, using wp_redirect().
    1273  *
    1274  * Checks whether the $location is using an allowed host, if it has an absolute
    1275  * path. A plugin can therefore set or remove allowed host(s) to or from the
    1276  * list.
    1277  *
    1278  * If the host is not allowed, then the redirect defaults to wp-admin on the siteurl
    1279  * instead. This prevents malicious redirects which redirect to another host,
    1280  * but only used in a few places.
    1281  *
    1282  * Note: wp_safe_redirect() does not exit automatically, and should almost always be
    1283  * followed by a call to `exit;`:
    1284  *
    1285  *     wp_safe_redirect( $url );
    1286  *     exit;
    1287  *
    1288  * Exiting can also be selectively manipulated by using wp_safe_redirect() as a conditional
    1289  * in conjunction with the {@see 'wp_redirect'} and {@see 'wp_redirect_location'} filters:
    1290  *
    1291  *     if ( wp_safe_redirect( $url ) ) {
    1292  *         exit;
    1293  *     }
    1294  *
    1295  * @since 2.3.0
    1296  * @since 5.0.0 The return value from wp_redirect() is now passed on.
    1297  *
    1298  * @param string $location The path or URL to redirect to.
    1299  * @param int    $status   Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
    1300  * @return bool  $redirect False if the redirect was cancelled, true otherwise.
    1301  */
    1302 function wp_safe_redirect($location, $status = 302) {
    1303 
    1304     // Need to look at the URL the way it will end up in wp_redirect()
    1305     $location = wp_sanitize_redirect($location);
    1306 
    1307     /**
    1308      * Filters the redirect fallback URL for when the provided redirect is not safe (local).
    1309      *
    1310      * @since 4.3.0
    1311      *
    1312      * @param string $fallback_url The fallback URL to use by default.
    1313      * @param int    $status       The HTTP response status code to use.
    1314      */
    1315     $location = wp_validate_redirect( $location, apply_filters( 'wp_safe_redirect_fallback', admin_url(), $status ) );
    1316 
    1317     return wp_redirect( $location, $status );
    1318 }
    1319 endif;
    1320 
    1321 if ( !function_exists('wp_validate_redirect') ) :
    1322 /**
    1323  * Validates a URL for use in a redirect.
    1324  *
    1325  * Checks whether the $location is using an allowed host, if it has an absolute
    1326  * path. A plugin can therefore set or remove allowed host(s) to or from the
    1327  * list.
    1328  *
    1329  * If the host is not allowed, then the redirect is to $default supplied
    1330  *
    1331  * @since 2.8.1
    1332  *
    1333  * @param string $location The redirect to validate
    1334  * @param string $default  The value to return if $location is not allowed
    1335  * @return string redirect-sanitized URL
    1336  **/
    1337 function wp_validate_redirect($location, $default = '') {
    1338     $location = trim( $location, " \t\n\r\0\x08\x0B" );
    1339     // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
    1340     if ( substr($location, 0, 2) == '//' )
    1341         $location = 'http:' . $location;
    1342 
    1343     // In php 5 parse_url may fail if the URL query part contains http://, bug #38143
    1344     $test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location;
    1345 
    1346     // @-operator is used to prevent possible warnings in PHP < 5.3.3.
    1347     $lp = @parse_url($test);
    1348 
    1349     // Give up if malformed URL
    1350     if ( false === $lp )
    1351         return $default;
    1352 
    1353     // Allow only http and https schemes. No data:, etc.
    1354     if ( isset($lp['scheme']) && !('http' == $lp['scheme'] || 'https' == $lp['scheme']) )
    1355         return $default;
    1356 
    1357     // 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.
    1358     if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
    1359         return $default;
    1360     }
    1361 
    1362     // Reject malformed components parse_url() can return on odd inputs.
    1363     foreach ( array( 'user', 'pass', 'host' ) as $component ) {
    1364         if ( isset( $lp[ $component ] ) && strpbrk( $lp[ $component ], ':/?#@' ) ) {
     1257        $location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
     1258        $location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location );
     1259        $location = wp_kses_no_null( $location );
     1260
     1261        // remove %0d and %0a from location
     1262        $strip = array( '%0d', '%0a', '%0D', '%0A' );
     1263        return _deep_replace( $strip, $location );
     1264    }
     1265
     1266    /**
     1267     * URL encode UTF-8 characters in a URL.
     1268     *
     1269     * @ignore
     1270     * @since 4.2.0
     1271     * @access private
     1272     *
     1273     * @see wp_sanitize_redirect()
     1274     *
     1275     * @param array $matches RegEx matches against the redirect location.
     1276     * @return string URL-encoded version of the first RegEx match.
     1277     */
     1278    function _wp_sanitize_utf8_in_redirect( $matches ) {
     1279        return urlencode( $matches[0] );
     1280    }
     1281endif;
     1282
     1283if ( ! function_exists( 'wp_safe_redirect' ) ) :
     1284    /**
     1285     * Performs a safe (local) redirect, using wp_redirect().
     1286     *
     1287     * Checks whether the $location is using an allowed host, if it has an absolute
     1288     * path. A plugin can therefore set or remove allowed host(s) to or from the
     1289     * list.
     1290     *
     1291     * If the host is not allowed, then the redirect defaults to wp-admin on the siteurl
     1292     * instead. This prevents malicious redirects which redirect to another host,
     1293     * but only used in a few places.
     1294     *
     1295     * Note: wp_safe_redirect() does not exit automatically, and should almost always be
     1296     * followed by a call to `exit;`:
     1297     *
     1298     *     wp_safe_redirect( $url );
     1299     *     exit;
     1300     *
     1301     * Exiting can also be selectively manipulated by using wp_safe_redirect() as a conditional
     1302     * in conjunction with the {@see 'wp_redirect'} and {@see 'wp_redirect_location'} filters:
     1303     *
     1304     *     if ( wp_safe_redirect( $url ) ) {
     1305     *         exit;
     1306     *     }
     1307     *
     1308     * @since 2.3.0
     1309     * @since 5.0.0 The return value from wp_redirect() is now passed on.
     1310     *
     1311     * @param string $location The path or URL to redirect to.
     1312     * @param int    $status   Optional. HTTP response status code to use. Default '302' (Moved Temporarily).
     1313     * @return bool  $redirect False if the redirect was cancelled, true otherwise.
     1314     */
     1315    function wp_safe_redirect( $location, $status = 302 ) {
     1316
     1317        // Need to look at the URL the way it will end up in wp_redirect()
     1318        $location = wp_sanitize_redirect( $location );
     1319
     1320        /**
     1321         * Filters the redirect fallback URL for when the provided redirect is not safe (local).
     1322         *
     1323         * @since 4.3.0
     1324         *
     1325         * @param string $fallback_url The fallback URL to use by default.
     1326         * @param int    $status       The HTTP response status code to use.
     1327         */
     1328        $location = wp_validate_redirect( $location, apply_filters( 'wp_safe_redirect_fallback', admin_url(), $status ) );
     1329
     1330        return wp_redirect( $location, $status );
     1331    }
     1332endif;
     1333
     1334if ( ! function_exists( 'wp_validate_redirect' ) ) :
     1335    /**
     1336     * Validates a URL for use in a redirect.
     1337     *
     1338     * Checks whether the $location is using an allowed host, if it has an absolute
     1339     * path. A plugin can therefore set or remove allowed host(s) to or from the
     1340     * list.
     1341     *
     1342     * If the host is not allowed, then the redirect is to $default supplied
     1343     *
     1344     * @since 2.8.1
     1345     *
     1346     * @param string $location The redirect to validate
     1347     * @param string $default  The value to return if $location is not allowed
     1348     * @return string redirect-sanitized URL
     1349     */
     1350    function wp_validate_redirect( $location, $default = '' ) {
     1351        $location = trim( $location, " \t\n\r\0\x08\x0B" );
     1352        // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
     1353        if ( substr( $location, 0, 2 ) == '//' ) {
     1354            $location = 'http:' . $location;
     1355        }
     1356
     1357        // In php 5 parse_url may fail if the URL query part contains http://, bug #38143
     1358        $test = ( $cut = strpos( $location, '?' ) ) ? substr( $location, 0, $cut ) : $location;
     1359
     1360        // @-operator is used to prevent possible warnings in PHP < 5.3.3.
     1361        $lp = @parse_url( $test );
     1362
     1363        // Give up if malformed URL
     1364        if ( false === $lp ) {
    13651365            return $default;
    13661366        }
    1367     }
    1368 
    1369     $wpp = parse_url(home_url());
    1370 
    1371     /**
    1372      * Filters the whitelist of hosts to redirect to.
    1373      *
    1374      * @since 2.3.0
    1375      *
    1376      * @param array       $hosts An array of allowed hosts.
    1377      * @param bool|string $host  The parsed host; empty if not isset.
    1378      */
    1379     $allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : '' );
    1380 
    1381     if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) )
    1382         $location = $default;
    1383 
    1384     return $location;
    1385 }
    1386 endif;
    1387 
    1388 if ( ! function_exists('wp_notify_postauthor') ) :
    1389 /**
    1390  * Notify an author (and/or others) of a comment/trackback/pingback on a post.
    1391  *
    1392  * @since 1.0.0
    1393  *
    1394  * @param int|WP_Comment  $comment_id Comment ID or WP_Comment object.
    1395  * @param string          $deprecated Not used
    1396  * @return bool True on completion. False if no email addresses were specified.
    1397  */
    1398 function wp_notify_postauthor( $comment_id, $deprecated = null ) {
    1399     if ( null !== $deprecated ) {
    1400         _deprecated_argument( __FUNCTION__, '3.8.0' );
    1401     }
    1402 
    1403     $comment = get_comment( $comment_id );
    1404     if ( empty( $comment ) || empty( $comment->comment_post_ID ) )
    1405         return false;
    1406 
    1407     $post    = get_post( $comment->comment_post_ID );
    1408     $author  = get_userdata( $post->post_author );
    1409 
    1410     // Who to notify? By default, just the post author, but others can be added.
    1411     $emails = array();
    1412     if ( $author ) {
    1413         $emails[] = $author->user_email;
    1414     }
    1415 
    1416     /**
    1417      * Filters the list of email addresses to receive a comment notification.
    1418      *
    1419      * By default, only post authors are notified of comments. This filter allows
    1420      * others to be added.
    1421      *
    1422      * @since 3.7.0
    1423      *
    1424      * @param array $emails     An array of email addresses to receive a comment notification.
    1425      * @param int   $comment_id The comment ID.
    1426      */
    1427     $emails = apply_filters( 'comment_notification_recipients', $emails, $comment->comment_ID );
    1428     $emails = array_filter( $emails );
    1429 
    1430     // If there are no addresses to send the comment to, bail.
    1431     if ( ! count( $emails ) ) {
    1432         return false;
    1433     }
    1434 
    1435     // Facilitate unsetting below without knowing the keys.
    1436     $emails = array_flip( $emails );
    1437 
    1438     /**
    1439      * Filters whether to notify comment authors of their comments on their own posts.
    1440      *
    1441      * By default, comment authors aren't notified of their comments on their own
    1442      * posts. This filter allows you to override that.
    1443      *
    1444      * @since 3.8.0
    1445      *
    1446      * @param bool $notify     Whether to notify the post author of their own comment.
    1447      *                         Default false.
    1448      * @param int  $comment_id The comment ID.
    1449      */
    1450     $notify_author = apply_filters( 'comment_notification_notify_author', false, $comment->comment_ID );
    1451 
    1452     // The comment was left by the author
    1453     if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
    1454         unset( $emails[ $author->user_email ] );
    1455     }
    1456 
    1457     // The author moderated a comment on their own post
    1458     if ( $author && ! $notify_author && $post->post_author == get_current_user_id() ) {
    1459         unset( $emails[ $author->user_email ] );
    1460     }
    1461 
    1462     // The post author is no longer a member of the blog
    1463     if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
    1464         unset( $emails[ $author->user_email ] );
    1465     }
    1466 
    1467     // If there's no email to send the comment to, bail, otherwise flip array back around for use below
    1468     if ( ! count( $emails ) ) {
    1469         return false;
    1470     } else {
     1367
     1368        // Allow only http and https schemes. No data:, etc.
     1369        if ( isset( $lp['scheme'] ) && ! ( 'http' == $lp['scheme'] || 'https' == $lp['scheme'] ) ) {
     1370            return $default;
     1371        }
     1372
     1373        // 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.
     1374        if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
     1375            return $default;
     1376        }
     1377
     1378        // Reject malformed components parse_url() can return on odd inputs.
     1379        foreach ( array( 'user', 'pass', 'host' ) as $component ) {
     1380            if ( isset( $lp[ $component ] ) && strpbrk( $lp[ $component ], ':/?#@' ) ) {
     1381                return $default;
     1382            }
     1383        }
     1384
     1385        $wpp = parse_url( home_url() );
     1386
     1387        /**
     1388         * Filters the whitelist of hosts to redirect to.
     1389         *
     1390         * @since 2.3.0
     1391         *
     1392         * @param array       $hosts An array of allowed hosts.
     1393         * @param bool|string $host  The parsed host; empty if not isset.
     1394         */
     1395        $allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array( $wpp['host'] ), isset( $lp['host'] ) ? $lp['host'] : '' );
     1396
     1397        if ( isset( $lp['host'] ) && ( ! in_array( $lp['host'], $allowed_hosts ) && $lp['host'] != strtolower( $wpp['host'] ) ) ) {
     1398            $location = $default;
     1399        }
     1400
     1401        return $location;
     1402    }
     1403endif;
     1404
     1405if ( ! function_exists( 'wp_notify_postauthor' ) ) :
     1406    /**
     1407     * Notify an author (and/or others) of a comment/trackback/pingback on a post.
     1408     *
     1409     * @since 1.0.0
     1410     *
     1411     * @param int|WP_Comment  $comment_id Comment ID or WP_Comment object.
     1412     * @param string          $deprecated Not used
     1413     * @return bool True on completion. False if no email addresses were specified.
     1414     */
     1415    function wp_notify_postauthor( $comment_id, $deprecated = null ) {
     1416        if ( null !== $deprecated ) {
     1417            _deprecated_argument( __FUNCTION__, '3.8.0' );
     1418        }
     1419
     1420        $comment = get_comment( $comment_id );
     1421        if ( empty( $comment ) || empty( $comment->comment_post_ID ) ) {
     1422            return false;
     1423        }
     1424
     1425        $post   = get_post( $comment->comment_post_ID );
     1426        $author = get_userdata( $post->post_author );
     1427
     1428        // Who to notify? By default, just the post author, but others can be added.
     1429        $emails = array();
     1430        if ( $author ) {
     1431            $emails[] = $author->user_email;
     1432        }
     1433
     1434        /**
     1435         * Filters the list of email addresses to receive a comment notification.
     1436         *
     1437         * By default, only post authors are notified of comments. This filter allows
     1438         * others to be added.
     1439         *
     1440         * @since 3.7.0
     1441         *
     1442         * @param array $emails     An array of email addresses to receive a comment notification.
     1443         * @param int   $comment_id The comment ID.
     1444         */
     1445        $emails = apply_filters( 'comment_notification_recipients', $emails, $comment->comment_ID );
     1446        $emails = array_filter( $emails );
     1447
     1448        // If there are no addresses to send the comment to, bail.
     1449        if ( ! count( $emails ) ) {
     1450            return false;
     1451        }
     1452
     1453        // Facilitate unsetting below without knowing the keys.
    14711454        $emails = array_flip( $emails );
    1472     }
    1473 
    1474     $switched_locale = switch_to_locale( get_locale() );
    1475 
    1476     $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
    1477 
    1478     // The blogname option is escaped with esc_html on the way into the database in sanitize_option
    1479     // we want to reverse this for the plain text arena of emails.
    1480     $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
    1481     $comment_content = wp_specialchars_decode( $comment->comment_content );
    1482 
    1483     switch ( $comment->comment_type ) {
    1484         case 'trackback':
    1485             /* translators: 1: Post title */
    1486             $notify_message  = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
    1487             /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
    1488             $notify_message .= sprintf( __('Website: %1$s (IP address: %2$s, %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1489             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1490             $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
    1491             $notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
    1492             /* translators: 1: blog name, 2: post title */
    1493             $subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
    1494             break;
    1495         case 'pingback':
    1496             /* translators: 1: Post title */
    1497             $notify_message  = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
    1498             /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
    1499             $notify_message .= sprintf( __('Website: %1$s (IP address: %2$s, %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1500             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1501             $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
    1502             $notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
    1503             /* translators: 1: blog name, 2: post title */
    1504             $subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
    1505             break;
    1506         default: // Comments
    1507             $notify_message  = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
    1508             /* translators: 1: comment author, 2: comment author's IP address, 3: comment author's hostname */
    1509             $notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1510             $notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
    1511             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1512             $notify_message .= sprintf( __('Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
    1513             $notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
    1514             /* translators: 1: blog name, 2: post title */
    1515             $subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
    1516             break;
    1517     }
    1518     $notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
    1519     $notify_message .= sprintf( __('Permalink: %s'), get_comment_link( $comment ) ) . "\r\n";
    1520 
    1521     if ( user_can( $post->post_author, 'edit_comment', $comment->comment_ID ) ) {
    1522         if ( EMPTY_TRASH_DAYS ) {
    1523             $notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
     1455
     1456        /**
     1457         * Filters whether to notify comment authors of their comments on their own posts.
     1458         *
     1459         * By default, comment authors aren't notified of their comments on their own
     1460         * posts. This filter allows you to override that.
     1461         *
     1462         * @since 3.8.0
     1463         *
     1464         * @param bool $notify     Whether to notify the post author of their own comment.
     1465         *                         Default false.
     1466         * @param int  $comment_id The comment ID.
     1467         */
     1468        $notify_author = apply_filters( 'comment_notification_notify_author', false, $comment->comment_ID );
     1469
     1470        // The comment was left by the author
     1471        if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
     1472            unset( $emails[ $author->user_email ] );
     1473        }
     1474
     1475        // The author moderated a comment on their own post
     1476        if ( $author && ! $notify_author && $post->post_author == get_current_user_id() ) {
     1477            unset( $emails[ $author->user_email ] );
     1478        }
     1479
     1480        // The post author is no longer a member of the blog
     1481        if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
     1482            unset( $emails[ $author->user_email ] );
     1483        }
     1484
     1485        // If there's no email to send the comment to, bail, otherwise flip array back around for use below
     1486        if ( ! count( $emails ) ) {
     1487            return false;
    15241488        } else {
    1525             $notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
    1526         }
    1527         $notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
    1528     }
    1529 
    1530     $wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
    1531 
    1532     if ( '' == $comment->comment_author ) {
    1533         $from = "From: \"$blogname\" <$wp_email>";
    1534         if ( '' != $comment->comment_author_email )
    1535             $reply_to = "Reply-To: $comment->comment_author_email";
    1536     } else {
    1537         $from = "From: \"$comment->comment_author\" <$wp_email>";
    1538         if ( '' != $comment->comment_author_email )
    1539             $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
    1540     }
    1541 
    1542     $message_headers = "$from\n"
    1543         . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
    1544 
    1545     if ( isset($reply_to) )
    1546         $message_headers .= $reply_to . "\n";
    1547 
    1548     /**
    1549      * Filters the comment notification email text.
    1550      *
    1551      * @since 1.5.2
    1552      *
    1553      * @param string $notify_message The comment notification email text.
    1554      * @param int    $comment_id     Comment ID.
    1555      */
    1556     $notify_message = apply_filters( 'comment_notification_text', $notify_message, $comment->comment_ID );
    1557 
    1558     /**
    1559      * Filters the comment notification email subject.
    1560      *
    1561      * @since 1.5.2
    1562      *
    1563      * @param string $subject    The comment notification email subject.
    1564      * @param int    $comment_id Comment ID.
    1565      */
    1566     $subject = apply_filters( 'comment_notification_subject', $subject, $comment->comment_ID );
    1567 
    1568     /**
    1569      * Filters the comment notification email headers.
    1570      *
    1571      * @since 1.5.2
    1572      *
    1573      * @param string $message_headers Headers for the comment notification email.
    1574      * @param int    $comment_id      Comment ID.
    1575      */
    1576     $message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment->comment_ID );
    1577 
    1578     foreach ( $emails as $email ) {
    1579         @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
    1580     }
    1581 
    1582     if ( $switched_locale ) {
    1583         restore_previous_locale();
    1584     }
    1585 
    1586     return true;
    1587 }
    1588 endif;
    1589 
    1590 if ( !function_exists('wp_notify_moderator') ) :
    1591 /**
    1592  * Notifies the moderator of the site about a new comment that is awaiting approval.
    1593  *
    1594  * @since 1.0.0
    1595  *
    1596  * @global wpdb $wpdb WordPress database abstraction object.
    1597  *
    1598  * Uses the {@see 'notify_moderator'} filter to determine whether the site moderator
    1599  * should be notified, overriding the site setting.
    1600  *
    1601  * @param int $comment_id Comment ID.
    1602  * @return true Always returns true.
    1603  */
    1604 function wp_notify_moderator($comment_id) {
    1605     global $wpdb;
    1606 
    1607     $maybe_notify = get_option( 'moderation_notify' );
    1608 
    1609     /**
    1610      * Filters whether to send the site moderator email notifications, overriding the site setting.
    1611      *
    1612      * @since 4.4.0
    1613      *
    1614      * @param bool $maybe_notify Whether to notify blog moderator.
    1615      * @param int  $comment_ID   The id of the comment for the notification.
    1616      */
    1617     $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id );
    1618 
    1619     if ( ! $maybe_notify ) {
    1620         return true;
    1621     }
    1622 
    1623     $comment = get_comment($comment_id);
    1624     $post = get_post($comment->comment_post_ID);
    1625     $user = get_userdata( $post->post_author );
    1626     // Send to the administration and to the post author if the author can modify the comment.
    1627     $emails = array( get_option( 'admin_email' ) );
    1628     if ( $user && user_can( $user->ID, 'edit_comment', $comment_id ) && ! empty( $user->user_email ) ) {
    1629         if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) )
    1630             $emails[] = $user->user_email;
    1631     }
    1632 
    1633     $switched_locale = switch_to_locale( get_locale() );
    1634 
    1635     $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
    1636     $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
    1637 
    1638     // The blogname option is escaped with esc_html on the way into the database in sanitize_option
    1639     // we want to reverse this for the plain text arena of emails.
    1640     $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
    1641     $comment_content = wp_specialchars_decode( $comment->comment_content );
    1642 
    1643     switch ( $comment->comment_type ) {
    1644         case 'trackback':
    1645             /* translators: 1: Post title */
    1646             $notify_message  = sprintf( __('A new trackback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
    1647             $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
    1648             /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
    1649             $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1650             /* translators: 1: Trackback/pingback/comment author URL */
    1651             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1652             $notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment_content . "\r\n\r\n";
    1653             break;
    1654         case 'pingback':
    1655             /* translators: 1: Post title */
    1656             $notify_message  = sprintf( __('A new pingback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
    1657             $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
    1658             /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
    1659             $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1660             /* translators: 1: Trackback/pingback/comment author URL */
    1661             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1662             $notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment_content . "\r\n\r\n";
    1663             break;
    1664         default: // Comments
    1665             /* translators: 1: Post title */
    1666             $notify_message  = sprintf( __('A new comment on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
    1667             $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
    1668             /* translators: 1: Comment author name, 2: comment author's IP address, 3: comment author's hostname */
    1669             $notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
    1670             /* translators: 1: Comment author URL */
    1671             $notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
    1672             /* translators: 1: Trackback/pingback/comment author URL */
    1673             $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
    1674             /* translators: 1: Comment text */
    1675             $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
    1676             break;
    1677     }
    1678 
    1679     /* translators: Comment moderation. 1: Comment action URL */
    1680     $notify_message .= sprintf( __( 'Approve it: %s' ), admin_url( "comment.php?action=approve&c={$comment_id}#wpbody-content" ) ) . "\r\n";
    1681 
    1682     if ( EMPTY_TRASH_DAYS ) {
    1683         /* translators: Comment moderation. 1: Comment action URL */
    1684         $notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment_id}#wpbody-content" ) ) . "\r\n";
    1685     } else {
    1686         /* translators: Comment moderation. 1: Comment action URL */
    1687         $notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment_id}#wpbody-content" ) ) . "\r\n";
    1688     }
    1689 
    1690     /* translators: Comment moderation. 1: Comment action URL */
    1691     $notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment_id}#wpbody-content" ) ) . "\r\n";
    1692 
    1693     /* translators: Comment moderation. 1: Number of comments awaiting approval */
    1694     $notify_message .= sprintf( _n('Currently %s comment is waiting for approval. Please visit the moderation panel:',
    1695         'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
    1696     $notify_message .= admin_url( "edit-comments.php?comment_status=moderated#wpbody-content" ) . "\r\n";
    1697 
    1698     /* translators: Comment moderation notification email subject. 1: Site name, 2: Post title */
    1699     $subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), $blogname, $post->post_title );
    1700     $message_headers = '';
    1701 
    1702     /**
    1703      * Filters the list of recipients for comment moderation emails.
    1704      *
    1705      * @since 3.7.0
    1706      *
    1707      * @param array $emails     List of email addresses to notify for comment moderation.
    1708      * @param int   $comment_id Comment ID.
    1709      */
    1710     $emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
    1711 
    1712     /**
    1713      * Filters the comment moderation email text.
    1714      *
    1715      * @since 1.5.2
    1716      *
    1717      * @param string $notify_message Text of the comment moderation email.
    1718      * @param int    $comment_id     Comment ID.
    1719      */
    1720     $notify_message = apply_filters( 'comment_moderation_text', $notify_message, $comment_id );
    1721 
    1722     /**
    1723      * Filters the comment moderation email subject.
    1724      *
    1725      * @since 1.5.2
    1726      *
    1727      * @param string $subject    Subject of the comment moderation email.
    1728      * @param int    $comment_id Comment ID.
    1729      */
    1730     $subject = apply_filters( 'comment_moderation_subject', $subject, $comment_id );
    1731 
    1732     /**
    1733      * Filters the comment moderation email headers.
    1734      *
    1735      * @since 2.8.0
    1736      *
    1737      * @param string $message_headers Headers for the comment moderation email.
    1738      * @param int    $comment_id      Comment ID.
    1739      */
    1740     $message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
    1741 
    1742     foreach ( $emails as $email ) {
    1743         @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
    1744     }
    1745 
    1746     if ( $switched_locale ) {
    1747         restore_previous_locale();
    1748     }
    1749 
    1750     return true;
    1751 }
    1752 endif;
    1753 
    1754 if ( !function_exists('wp_password_change_notification') ) :
    1755 /**
    1756  * Notify the blog admin of a user changing password, normally via email.
    1757  *
    1758  * @since 2.7.0
    1759  *
    1760  * @param WP_User $user User object.
    1761  */
    1762 function wp_password_change_notification( $user ) {
    1763     // send a copy of password change notification to the admin
    1764     // but check to see if it's the admin whose password we're changing, and skip this
    1765     if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
    1766         /* translators: %s: user name */
    1767         $message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
     1489            $emails = array_flip( $emails );
     1490        }
     1491
     1492        $switched_locale = switch_to_locale( get_locale() );
     1493
     1494        $comment_author_domain = @gethostbyaddr( $comment->comment_author_IP );
     1495
    17681496        // The blogname option is escaped with esc_html on the way into the database in sanitize_option
    17691497        // we want to reverse this for the plain text arena of emails.
    1770         $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
    1771 
    1772         $wp_password_change_notification_email = array(
    1773             'to'      => get_option( 'admin_email' ),
     1498        $blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
     1499        $comment_content = wp_specialchars_decode( $comment->comment_content );
     1500
     1501        switch ( $comment->comment_type ) {
     1502            case 'trackback':
     1503                /* translators: 1: Post title */
     1504                $notify_message = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
     1505                /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
     1506                $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1507                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1508                $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
     1509                $notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
     1510                /* translators: 1: blog name, 2: post title */
     1511                $subject = sprintf( __( '[%1$s] Trackback: "%2$s"' ), $blogname, $post->post_title );
     1512                break;
     1513            case 'pingback':
     1514                /* translators: 1: Post title */
     1515                $notify_message = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
     1516                /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
     1517                $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1518                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1519                $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
     1520                $notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
     1521                /* translators: 1: blog name, 2: post title */
     1522                $subject = sprintf( __( '[%1$s] Pingback: "%2$s"' ), $blogname, $post->post_title );
     1523                break;
     1524            default: // Comments
     1525                $notify_message = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
     1526                /* translators: 1: comment author, 2: comment author's IP address, 3: comment author's hostname */
     1527                $notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1528                $notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
     1529                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1530                $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
     1531                $notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
     1532                /* translators: 1: blog name, 2: post title */
     1533                $subject = sprintf( __( '[%1$s] Comment: "%2$s"' ), $blogname, $post->post_title );
     1534                break;
     1535        }
     1536        $notify_message .= get_permalink( $comment->comment_post_ID ) . "#comments\r\n\r\n";
     1537        $notify_message .= sprintf( __( 'Permalink: %s' ), get_comment_link( $comment ) ) . "\r\n";
     1538
     1539        if ( user_can( $post->post_author, 'edit_comment', $comment->comment_ID ) ) {
     1540            if ( EMPTY_TRASH_DAYS ) {
     1541                $notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
     1542            } else {
     1543                $notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
     1544            }
     1545            $notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
     1546        }
     1547
     1548        $wp_email = 'wordpress@' . preg_replace( '#^www\.#', '', strtolower( $_SERVER['SERVER_NAME'] ) );
     1549
     1550        if ( '' == $comment->comment_author ) {
     1551            $from = "From: \"$blogname\" <$wp_email>";
     1552            if ( '' != $comment->comment_author_email ) {
     1553                $reply_to = "Reply-To: $comment->comment_author_email";
     1554            }
     1555        } else {
     1556            $from = "From: \"$comment->comment_author\" <$wp_email>";
     1557            if ( '' != $comment->comment_author_email ) {
     1558                $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
     1559            }
     1560        }
     1561
     1562        $message_headers = "$from\n"
     1563        . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
     1564
     1565        if ( isset( $reply_to ) ) {
     1566            $message_headers .= $reply_to . "\n";
     1567        }
     1568
     1569        /**
     1570         * Filters the comment notification email text.
     1571         *
     1572         * @since 1.5.2
     1573         *
     1574         * @param string $notify_message The comment notification email text.
     1575         * @param int    $comment_id     Comment ID.
     1576         */
     1577        $notify_message = apply_filters( 'comment_notification_text', $notify_message, $comment->comment_ID );
     1578
     1579        /**
     1580         * Filters the comment notification email subject.
     1581         *
     1582         * @since 1.5.2
     1583         *
     1584         * @param string $subject    The comment notification email subject.
     1585         * @param int    $comment_id Comment ID.
     1586         */
     1587        $subject = apply_filters( 'comment_notification_subject', $subject, $comment->comment_ID );
     1588
     1589        /**
     1590         * Filters the comment notification email headers.
     1591         *
     1592         * @since 1.5.2
     1593         *
     1594         * @param string $message_headers Headers for the comment notification email.
     1595         * @param int    $comment_id      Comment ID.
     1596         */
     1597        $message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment->comment_ID );
     1598
     1599        foreach ( $emails as $email ) {
     1600            @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
     1601        }
     1602
     1603        if ( $switched_locale ) {
     1604            restore_previous_locale();
     1605        }
     1606
     1607        return true;
     1608    }
     1609endif;
     1610
     1611if ( ! function_exists( 'wp_notify_moderator' ) ) :
     1612    /**
     1613     * Notifies the moderator of the site about a new comment that is awaiting approval.
     1614     *
     1615     * @since 1.0.0
     1616     *
     1617     * @global wpdb $wpdb WordPress database abstraction object.
     1618     *
     1619     * Uses the {@see 'notify_moderator'} filter to determine whether the site moderator
     1620     * should be notified, overriding the site setting.
     1621     *
     1622     * @param int $comment_id Comment ID.
     1623     * @return true Always returns true.
     1624     */
     1625    function wp_notify_moderator( $comment_id ) {
     1626        global $wpdb;
     1627
     1628        $maybe_notify = get_option( 'moderation_notify' );
     1629
     1630        /**
     1631         * Filters whether to send the site moderator email notifications, overriding the site setting.
     1632         *
     1633         * @since 4.4.0
     1634         *
     1635         * @param bool $maybe_notify Whether to notify blog moderator.
     1636         * @param int  $comment_ID   The id of the comment for the notification.
     1637         */
     1638        $maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id );
     1639
     1640        if ( ! $maybe_notify ) {
     1641            return true;
     1642        }
     1643
     1644        $comment = get_comment( $comment_id );
     1645        $post    = get_post( $comment->comment_post_ID );
     1646        $user    = get_userdata( $post->post_author );
     1647        // Send to the administration and to the post author if the author can modify the comment.
     1648        $emails = array( get_option( 'admin_email' ) );
     1649        if ( $user && user_can( $user->ID, 'edit_comment', $comment_id ) && ! empty( $user->user_email ) ) {
     1650            if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
     1651                $emails[] = $user->user_email;
     1652            }
     1653        }
     1654
     1655        $switched_locale = switch_to_locale( get_locale() );
     1656
     1657        $comment_author_domain = @gethostbyaddr( $comment->comment_author_IP );
     1658        $comments_waiting      = $wpdb->get_var( "SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'" );
     1659
     1660        // The blogname option is escaped with esc_html on the way into the database in sanitize_option
     1661        // we want to reverse this for the plain text arena of emails.
     1662        $blogname        = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
     1663        $comment_content = wp_specialchars_decode( $comment->comment_content );
     1664
     1665        switch ( $comment->comment_type ) {
     1666            case 'trackback':
     1667                /* translators: 1: Post title */
     1668                $notify_message  = sprintf( __( 'A new trackback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
     1669                $notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
     1670                /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
     1671                $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1672                /* translators: 1: Trackback/pingback/comment author URL */
     1673                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1674                $notify_message .= __( 'Trackback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
     1675                break;
     1676            case 'pingback':
     1677                /* translators: 1: Post title */
     1678                $notify_message  = sprintf( __( 'A new pingback on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
     1679                $notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
     1680                /* translators: 1: Trackback/pingback website name, 2: website IP address, 3: website hostname */
     1681                $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1682                /* translators: 1: Trackback/pingback/comment author URL */
     1683                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1684                $notify_message .= __( 'Pingback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n";
     1685                break;
     1686            default: // Comments
     1687                /* translators: 1: Post title */
     1688                $notify_message  = sprintf( __( 'A new comment on the post "%s" is waiting for your approval' ), $post->post_title ) . "\r\n";
     1689                $notify_message .= get_permalink( $comment->comment_post_ID ) . "\r\n\r\n";
     1690                /* translators: 1: Comment author name, 2: comment author's IP address, 3: comment author's hostname */
     1691                $notify_message .= sprintf( __( 'Author: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
     1692                /* translators: 1: Comment author URL */
     1693                $notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
     1694                /* translators: 1: Trackback/pingback/comment author URL */
     1695                $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
     1696                /* translators: 1: Comment text */
     1697                $notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
     1698                break;
     1699        }
     1700
     1701        /* translators: Comment moderation. 1: Comment action URL */
     1702        $notify_message .= sprintf( __( 'Approve it: %s' ), admin_url( "comment.php?action=approve&c={$comment_id}#wpbody-content" ) ) . "\r\n";
     1703
     1704        if ( EMPTY_TRASH_DAYS ) {
     1705            /* translators: Comment moderation. 1: Comment action URL */
     1706            $notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment_id}#wpbody-content" ) ) . "\r\n";
     1707        } else {
     1708            /* translators: Comment moderation. 1: Comment action URL */
     1709            $notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment_id}#wpbody-content" ) ) . "\r\n";
     1710        }
     1711
     1712        /* translators: Comment moderation. 1: Comment action URL */
     1713        $notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment_id}#wpbody-content" ) ) . "\r\n";
     1714
     1715        /* translators: Comment moderation. 1: Number of comments awaiting approval */
     1716        $notify_message .= sprintf(
     1717            _n(
     1718                'Currently %s comment is waiting for approval. Please visit the moderation panel:',
     1719                'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting
     1720            ), number_format_i18n( $comments_waiting )
     1721        ) . "\r\n";
     1722        $notify_message .= admin_url( 'edit-comments.php?comment_status=moderated#wpbody-content' ) . "\r\n";
     1723
     1724        /* translators: Comment moderation notification email subject. 1: Site name, 2: Post title */
     1725        $subject         = sprintf( __( '[%1$s] Please moderate: "%2$s"' ), $blogname, $post->post_title );
     1726        $message_headers = '';
     1727
     1728        /**
     1729         * Filters the list of recipients for comment moderation emails.
     1730         *
     1731         * @since 3.7.0
     1732         *
     1733         * @param array $emails     List of email addresses to notify for comment moderation.
     1734         * @param int   $comment_id Comment ID.
     1735         */
     1736        $emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
     1737
     1738        /**
     1739         * Filters the comment moderation email text.
     1740         *
     1741         * @since 1.5.2
     1742         *
     1743         * @param string $notify_message Text of the comment moderation email.
     1744         * @param int    $comment_id     Comment ID.
     1745         */
     1746        $notify_message = apply_filters( 'comment_moderation_text', $notify_message, $comment_id );
     1747
     1748        /**
     1749         * Filters the comment moderation email subject.
     1750         *
     1751         * @since 1.5.2
     1752         *
     1753         * @param string $subject    Subject of the comment moderation email.
     1754         * @param int    $comment_id Comment ID.
     1755         */
     1756        $subject = apply_filters( 'comment_moderation_subject', $subject, $comment_id );
     1757
     1758        /**
     1759         * Filters the comment moderation email headers.
     1760         *
     1761         * @since 2.8.0
     1762         *
     1763         * @param string $message_headers Headers for the comment moderation email.
     1764         * @param int    $comment_id      Comment ID.
     1765         */
     1766        $message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
     1767
     1768        foreach ( $emails as $email ) {
     1769            @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
     1770        }
     1771
     1772        if ( $switched_locale ) {
     1773            restore_previous_locale();
     1774        }
     1775
     1776        return true;
     1777    }
     1778endif;
     1779
     1780if ( ! function_exists( 'wp_password_change_notification' ) ) :
     1781    /**
     1782     * Notify the blog admin of a user changing password, normally via email.
     1783     *
     1784     * @since 2.7.0
     1785     *
     1786     * @param WP_User $user User object.
     1787     */
     1788    function wp_password_change_notification( $user ) {
     1789        // send a copy of password change notification to the admin
     1790        // but check to see if it's the admin whose password we're changing, and skip this
     1791        if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
     1792            /* translators: %s: user name */
     1793            $message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
     1794            // The blogname option is escaped with esc_html on the way into the database in sanitize_option
     1795            // we want to reverse this for the plain text arena of emails.
     1796            $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
     1797
     1798            $wp_password_change_notification_email = array(
     1799                'to'      => get_option( 'admin_email' ),
     1800                /* translators: Password change notification email subject. %s: Site title */
     1801                'subject' => __( '[%s] Password Changed' ),
     1802                'message' => $message,
     1803                'headers' => '',
     1804            );
     1805
     1806            /**
     1807             * Filters the contents of the password change notification email sent to the site admin.
     1808             *
     1809             * @since 4.9.0
     1810             *
     1811             * @param array   $wp_password_change_notification_email {
     1812             *     Used to build wp_mail().
     1813             *
     1814             *     @type string $to      The intended recipient - site admin email address.
     1815             *     @type string $subject The subject of the email.
     1816             *     @type string $message The body of the email.
     1817             *     @type string $headers The headers of the email.
     1818             * }
     1819             * @param WP_User $user     User object for user whose password was changed.
     1820             * @param string  $blogname The site title.
     1821             */
     1822            $wp_password_change_notification_email = apply_filters( 'wp_password_change_notification_email', $wp_password_change_notification_email, $user, $blogname );
     1823
     1824            wp_mail(
     1825                $wp_password_change_notification_email['to'],
     1826                wp_specialchars_decode( sprintf( $wp_password_change_notification_email['subject'], $blogname ) ),
     1827                $wp_password_change_notification_email['message'],
     1828                $wp_password_change_notification_email['headers']
     1829            );
     1830        }
     1831    }
     1832endif;
     1833
     1834if ( ! function_exists( 'wp_new_user_notification' ) ) :
     1835    /**
     1836     * Email login credentials to a newly-registered user.
     1837     *
     1838     * A new user registration notification is also sent to admin email.
     1839     *
     1840     * @since 2.0.0
     1841     * @since 4.3.0 The `$plaintext_pass` parameter was changed to `$notify`.
     1842     * @since 4.3.1 The `$plaintext_pass` parameter was deprecated. `$notify` added as a third parameter.
     1843     * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
     1844     *
     1845     * @global wpdb         $wpdb      WordPress database object for queries.
     1846     * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
     1847     *
     1848     * @param int    $user_id    User ID.
     1849     * @param null   $deprecated Not used (argument deprecated).
     1850     * @param string $notify     Optional. Type of notification that should happen. Accepts 'admin' or an empty
     1851     *                           string (admin only), 'user', or 'both' (admin and user). Default empty.
     1852     */
     1853    function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
     1854        if ( $deprecated !== null ) {
     1855            _deprecated_argument( __FUNCTION__, '4.3.1' );
     1856        }
     1857
     1858        global $wpdb, $wp_hasher;
     1859        $user = get_userdata( $user_id );
     1860
     1861        // The blogname option is escaped with esc_html on the way into the database in sanitize_option
     1862        // we want to reverse this for the plain text arena of emails.
     1863        $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
     1864
     1865        if ( 'user' !== $notify ) {
     1866            $switched_locale = switch_to_locale( get_locale() );
     1867
     1868            /* translators: %s: site title */
     1869            $message = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
     1870            /* translators: %s: user login */
     1871            $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
     1872            /* translators: %s: user email address */
     1873            $message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
     1874
     1875            $wp_new_user_notification_email_admin = array(
     1876                'to'      => get_option( 'admin_email' ),
     1877                /* translators: Password change notification email subject. %s: Site title */
     1878                'subject' => __( '[%s] New User Registration' ),
     1879                'message' => $message,
     1880                'headers' => '',
     1881            );
     1882
     1883            /**
     1884             * Filters the contents of the new user notification email sent to the site admin.
     1885             *
     1886             * @since 4.9.0
     1887             *
     1888             * @param array   $wp_new_user_notification_email {
     1889             *     Used to build wp_mail().
     1890             *
     1891             *     @type string $to      The intended recipient - site admin email address.
     1892             *     @type string $subject The subject of the email.
     1893             *     @type string $message The body of the email.
     1894             *     @type string $headers The headers of the email.
     1895             * }
     1896             * @param WP_User $user     User object for new user.
     1897             * @param string  $blogname The site title.
     1898             */
     1899            $wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
     1900
     1901            @wp_mail(
     1902                $wp_new_user_notification_email_admin['to'],
     1903                wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
     1904                $wp_new_user_notification_email_admin['message'],
     1905                $wp_new_user_notification_email_admin['headers']
     1906            );
     1907
     1908            if ( $switched_locale ) {
     1909                restore_previous_locale();
     1910            }
     1911        }
     1912
     1913        // `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notification.
     1914        if ( 'admin' === $notify || ( empty( $deprecated ) && empty( $notify ) ) ) {
     1915            return;
     1916        }
     1917
     1918        // Generate something random for a password reset key.
     1919        $key = wp_generate_password( 20, false );
     1920
     1921        /** This action is documented in wp-login.php */
     1922        do_action( 'retrieve_password_key', $user->user_login, $key );
     1923
     1924        // Now insert the key, hashed, into the DB.
     1925        if ( empty( $wp_hasher ) ) {
     1926            require_once ABSPATH . WPINC . '/class-phpass.php';
     1927            $wp_hasher = new PasswordHash( 8, true );
     1928        }
     1929        $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
     1930        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
     1931
     1932        $switched_locale = switch_to_locale( get_user_locale( $user ) );
     1933
     1934        /* translators: %s: user login */
     1935        $message  = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
     1936        $message .= __( 'To set your password, visit the following address:' ) . "\r\n\r\n";
     1937        $message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user->user_login ), 'login' ) . ">\r\n\r\n";
     1938
     1939        $message .= wp_login_url() . "\r\n";
     1940
     1941        $wp_new_user_notification_email = array(
     1942            'to'      => $user->user_email,
    17741943            /* translators: Password change notification email subject. %s: Site title */
    1775             'subject' => __( '[%s] Password Changed' ),
     1944            'subject' => __( '[%s] Your username and password info' ),
    17761945            'message' => $message,
    17771946            'headers' => '',
     
    17791948
    17801949        /**
    1781          * Filters the contents of the password change notification email sent to the site admin.
    1782          *
    1783          * @since 4.9.0
    1784          *
    1785          * @param array   $wp_password_change_notification_email {
    1786          *     Used to build wp_mail().
    1787          *
    1788          *     @type string $to      The intended recipient - site admin email address.
    1789          *     @type string $subject The subject of the email.
    1790          *     @type string $message The body of the email.
    1791          *     @type string $headers The headers of the email.
    1792          * }
    1793          * @param WP_User $user     User object for user whose password was changed.
    1794          * @param string  $blogname The site title.
    1795          */
    1796         $wp_password_change_notification_email = apply_filters( 'wp_password_change_notification_email', $wp_password_change_notification_email, $user, $blogname );
    1797 
    1798         wp_mail(
    1799             $wp_password_change_notification_email['to'],
    1800             wp_specialchars_decode( sprintf( $wp_password_change_notification_email['subject'], $blogname ) ),
    1801             $wp_password_change_notification_email['message'],
    1802             $wp_password_change_notification_email['headers']
    1803         );
    1804     }
    1805 }
    1806 endif;
    1807 
    1808 if ( !function_exists('wp_new_user_notification') ) :
    1809 /**
    1810  * Email login credentials to a newly-registered user.
    1811  *
    1812  * A new user registration notification is also sent to admin email.
    1813  *
    1814  * @since 2.0.0
    1815  * @since 4.3.0 The `$plaintext_pass` parameter was changed to `$notify`.
    1816  * @since 4.3.1 The `$plaintext_pass` parameter was deprecated. `$notify` added as a third parameter.
    1817  * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
    1818  *
    1819  * @global wpdb         $wpdb      WordPress database object for queries.
    1820  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
    1821  *
    1822  * @param int    $user_id    User ID.
    1823  * @param null   $deprecated Not used (argument deprecated).
    1824  * @param string $notify     Optional. Type of notification that should happen. Accepts 'admin' or an empty
    1825  *                           string (admin only), 'user', or 'both' (admin and user). Default empty.
    1826  */
    1827 function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
    1828     if ( $deprecated !== null ) {
    1829         _deprecated_argument( __FUNCTION__, '4.3.1' );
    1830     }
    1831 
    1832     global $wpdb, $wp_hasher;
    1833     $user = get_userdata( $user_id );
    1834 
    1835     // The blogname option is escaped with esc_html on the way into the database in sanitize_option
    1836     // we want to reverse this for the plain text arena of emails.
    1837     $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
    1838 
    1839     if ( 'user' !== $notify ) {
    1840         $switched_locale = switch_to_locale( get_locale() );
    1841 
    1842         /* translators: %s: site title */
    1843         $message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
    1844         /* translators: %s: user login */
    1845         $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
    1846         /* translators: %s: user email address */
    1847         $message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
    1848 
    1849         $wp_new_user_notification_email_admin = array(
    1850             'to'      => get_option( 'admin_email' ),
    1851             /* translators: Password change notification email subject. %s: Site title */
    1852             'subject' => __( '[%s] New User Registration' ),
    1853             'message' => $message,
    1854             'headers' => '',
    1855         );
    1856 
    1857         /**
    1858          * Filters the contents of the new user notification email sent to the site admin.
     1950         * Filters the contents of the new user notification email sent to the new user.
    18591951         *
    18601952         * @since 4.9.0
     
    18631955         *     Used to build wp_mail().
    18641956         *
    1865          *     @type string $to      The intended recipient - site admin email address.
     1957         *     @type string $to      The intended recipient - New user email address.
    18661958         *     @type string $subject The subject of the email.
    18671959         *     @type string $message The body of the email.
     
    18711963         * @param string  $blogname The site title.
    18721964         */
    1873         $wp_new_user_notification_email_admin = apply_filters( 'wp_new_user_notification_email_admin', $wp_new_user_notification_email_admin, $user, $blogname );
    1874 
    1875         @wp_mail(
    1876             $wp_new_user_notification_email_admin['to'],
    1877             wp_specialchars_decode( sprintf( $wp_new_user_notification_email_admin['subject'], $blogname ) ),
    1878             $wp_new_user_notification_email_admin['message'],
    1879             $wp_new_user_notification_email_admin['headers']
     1965        $wp_new_user_notification_email = apply_filters( 'wp_new_user_notification_email', $wp_new_user_notification_email, $user, $blogname );
     1966
     1967        wp_mail(
     1968            $wp_new_user_notification_email['to'],
     1969            wp_specialchars_decode( sprintf( $wp_new_user_notification_email['subject'], $blogname ) ),
     1970            $wp_new_user_notification_email['message'],
     1971            $wp_new_user_notification_email['headers']
    18801972        );
    18811973
     
    18841976        }
    18851977    }
    1886 
    1887     // `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notification.
    1888     if ( 'admin' === $notify || ( empty( $deprecated ) && empty( $notify ) ) ) {
    1889         return;
    1890     }
    1891 
    1892     // Generate something random for a password reset key.
    1893     $key = wp_generate_password( 20, false );
    1894 
    1895     /** This action is documented in wp-login.php */
    1896     do_action( 'retrieve_password_key', $user->user_login, $key );
    1897 
    1898     // Now insert the key, hashed, into the DB.
    1899     if ( empty( $wp_hasher ) ) {
    1900         require_once ABSPATH . WPINC . '/class-phpass.php';
    1901         $wp_hasher = new PasswordHash( 8, true );
    1902     }
    1903     $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
    1904     $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
    1905 
    1906     $switched_locale = switch_to_locale( get_user_locale( $user ) );
    1907 
    1908     /* translators: %s: user login */
    1909     $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
    1910     $message .= __('To set your password, visit the following address:') . "\r\n\r\n";
    1911     $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user->user_login), 'login') . ">\r\n\r\n";
    1912 
    1913     $message .= wp_login_url() . "\r\n";
    1914 
    1915     $wp_new_user_notification_email = array(
    1916         'to'      => $user->user_email,
    1917         /* translators: Password change notification email subject. %s: Site title */
    1918         'subject' => __( '[%s] Your username and password info' ),
    1919         'message' => $message,
    1920         'headers' => '',
    1921     );
    1922 
    1923     /**
    1924      * Filters the contents of the new user notification email sent to the new user.
    1925      *
    1926      * @since 4.9.0
    1927      *
    1928      * @param array   $wp_new_user_notification_email {
    1929      *     Used to build wp_mail().
    1930      *
    1931      *     @type string $to      The intended recipient - New user email address.
    1932      *     @type string $subject The subject of the email.
    1933      *     @type string $message The body of the email.
    1934      *     @type string $headers The headers of the email.
    1935      * }
    1936      * @param WP_User $user     User object for new user.
    1937      * @param string  $blogname The site title.
    1938      */
    1939     $wp_new_user_notification_email = apply_filters( 'wp_new_user_notification_email', $wp_new_user_notification_email, $user, $blogname );
    1940 
    1941     wp_mail(
    1942         $wp_new_user_notification_email['to'],
    1943         wp_specialchars_decode( sprintf( $wp_new_user_notification_email['subject'], $blogname ) ),
    1944         $wp_new_user_notification_email['message'],
    1945         $wp_new_user_notification_email['headers']
    1946     );
    1947 
    1948     if ( $switched_locale ) {
    1949         restore_previous_locale();
    1950     }
    1951 }
    1952 endif;
    1953 
    1954 if ( !function_exists('wp_nonce_tick') ) :
    1955 /**
    1956  * Get the time-dependent variable for nonce creation.
    1957  *
    1958  * A nonce has a lifespan of two ticks. Nonces in their second tick may be
    1959  * updated, e.g. by autosave.
    1960  *
    1961  * @since 2.5.0
    1962  *
    1963  * @return float Float value rounded up to the next highest integer.
    1964  */
    1965 function wp_nonce_tick() {
    1966     /**
    1967      * Filters the lifespan of nonces in seconds.
     1978endif;
     1979
     1980if ( ! function_exists( 'wp_nonce_tick' ) ) :
     1981    /**
     1982     * Get the time-dependent variable for nonce creation.
     1983     *
     1984     * A nonce has a lifespan of two ticks. Nonces in their second tick may be
     1985     * updated, e.g. by autosave.
    19681986     *
    19691987     * @since 2.5.0
    19701988     *
    1971      * @param int $lifespan Lifespan of nonces in seconds. Default 86,400 seconds, or one day.
    1972      */
    1973     $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
    1974 
    1975     return ceil(time() / ( $nonce_life / 2 ));
    1976 }
    1977 endif;
    1978 
    1979 if ( !function_exists('wp_verify_nonce') ) :
    1980 /**
    1981  * Verify that correct nonce was used with time limit.
    1982  *
    1983  * The user is given an amount of time to use the token, so therefore, since the
    1984  * UID and $action remain the same, the independent variable is the time.
    1985  *
    1986  * @since 2.0.3
    1987  *
    1988  * @param string     $nonce  Nonce that was used in the form to verify
    1989  * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
    1990  * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
    1991  *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
    1992  */
    1993 function wp_verify_nonce( $nonce, $action = -1 ) {
    1994     $nonce = (string) $nonce;
    1995     $user = wp_get_current_user();
    1996     $uid = (int) $user->ID;
    1997     if ( ! $uid ) {
    1998         /**
    1999          * Filters whether the user who generated the nonce is logged out.
    2000          *
    2001          * @since 3.5.0
    2002          *
    2003          * @param int    $uid    ID of the nonce-owning user.
    2004          * @param string $action The nonce action.
    2005          */
    2006         $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    2007     }
    2008 
    2009     if ( empty( $nonce ) ) {
     1989     * @return float Float value rounded up to the next highest integer.
     1990     */
     1991    function wp_nonce_tick() {
     1992        /**
     1993         * Filters the lifespan of nonces in seconds.
     1994         *
     1995         * @since 2.5.0
     1996         *
     1997         * @param int $lifespan Lifespan of nonces in seconds. Default 86,400 seconds, or one day.
     1998         */
     1999        $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
     2000
     2001        return ceil( time() / ( $nonce_life / 2 ) );
     2002    }
     2003endif;
     2004
     2005if ( ! function_exists( 'wp_verify_nonce' ) ) :
     2006    /**
     2007     * Verify that correct nonce was used with time limit.
     2008     *
     2009     * The user is given an amount of time to use the token, so therefore, since the
     2010     * UID and $action remain the same, the independent variable is the time.
     2011     *
     2012     * @since 2.0.3
     2013     *
     2014     * @param string     $nonce  Nonce that was used in the form to verify
     2015     * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
     2016     * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
     2017     *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
     2018     */
     2019    function wp_verify_nonce( $nonce, $action = -1 ) {
     2020        $nonce = (string) $nonce;
     2021        $user  = wp_get_current_user();
     2022        $uid   = (int) $user->ID;
     2023        if ( ! $uid ) {
     2024            /**
     2025             * Filters whether the user who generated the nonce is logged out.
     2026             *
     2027             * @since 3.5.0
     2028             *
     2029             * @param int    $uid    ID of the nonce-owning user.
     2030             * @param string $action The nonce action.
     2031             */
     2032            $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
     2033        }
     2034
     2035        if ( empty( $nonce ) ) {
     2036            return false;
     2037        }
     2038
     2039        $token = wp_get_session_token();
     2040        $i     = wp_nonce_tick();
     2041
     2042        // Nonce generated 0-12 hours ago
     2043        $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
     2044        if ( hash_equals( $expected, $nonce ) ) {
     2045            return 1;
     2046        }
     2047
     2048        // Nonce generated 12-24 hours ago
     2049        $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
     2050        if ( hash_equals( $expected, $nonce ) ) {
     2051            return 2;
     2052        }
     2053
     2054        /**
     2055         * Fires when nonce verification fails.
     2056         *
     2057         * @since 4.4.0
     2058         *
     2059         * @param string     $nonce  The invalid nonce.
     2060         * @param string|int $action The nonce action.
     2061         * @param WP_User    $user   The current user object.
     2062         * @param string     $token  The user's session token.
     2063         */
     2064        do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
     2065
     2066        // Invalid nonce
    20102067        return false;
    20112068    }
    2012 
    2013     $token = wp_get_session_token();
    2014     $i = wp_nonce_tick();
    2015 
    2016     // Nonce generated 0-12 hours ago
    2017     $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
    2018     if ( hash_equals( $expected, $nonce ) ) {
    2019         return 1;
    2020     }
    2021 
    2022     // Nonce generated 12-24 hours ago
    2023     $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
    2024     if ( hash_equals( $expected, $nonce ) ) {
    2025         return 2;
    2026     }
    2027 
    2028     /**
    2029      * Fires when nonce verification fails.
    2030      *
    2031      * @since 4.4.0
    2032      *
    2033      * @param string     $nonce  The invalid nonce.
    2034      * @param string|int $action The nonce action.
    2035      * @param WP_User    $user   The current user object.
    2036      * @param string     $token  The user's session token.
    2037      */
    2038     do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
    2039 
    2040     // Invalid nonce
    2041     return false;
    2042 }
    2043 endif;
    2044 
    2045 if ( !function_exists('wp_create_nonce') ) :
    2046 /**
    2047  * Creates a cryptographic token tied to a specific action, user, user session,
    2048  * and window of time.
    2049  *
    2050  * @since 2.0.3
    2051  * @since 4.0.0 Session tokens were integrated with nonce creation
    2052  *
    2053  * @param string|int $action Scalar value to add context to the nonce.
    2054  * @return string The token.
    2055  */
    2056 function wp_create_nonce($action = -1) {
    2057     $user = wp_get_current_user();
    2058     $uid = (int) $user->ID;
    2059     if ( ! $uid ) {
    2060         /** This filter is documented in wp-includes/pluggable.php */
    2061         $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    2062     }
    2063 
    2064     $token = wp_get_session_token();
    2065     $i = wp_nonce_tick();
    2066 
    2067     return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
    2068 }
    2069 endif;
    2070 
    2071 if ( !function_exists('wp_salt') ) :
    2072 /**
    2073  * Get salt to add to hashes.
    2074  *
    2075  * Salts are created using secret keys. Secret keys are located in two places:
    2076  * in the database and in the wp-config.php file. The secret key in the database
    2077  * is randomly generated and will be appended to the secret keys in wp-config.php.
    2078  *
    2079  * The secret keys in wp-config.php should be updated to strong, random keys to maximize
    2080  * security. Below is an example of how the secret key constants are defined.
    2081  * Do not paste this example directly into wp-config.php. Instead, have a
    2082  * {@link https://api.wordpress.org/secret-key/1.1/salt/ secret key created} just
    2083  * for you.
    2084  *
    2085  *     define('AUTH_KEY',         ' Xakm<o xQy rw4EMsLKM-?!T+,PFF})H4lzcW57AF0U@N@< >M%G4Yt>f`z]MON');
    2086  *     define('SECURE_AUTH_KEY',  'LzJ}op]mr|6+![P}Ak:uNdJCJZd>(Hx.-Mh#Tz)pCIU#uGEnfFz|f ;;eU%/U^O~');
    2087  *     define('LOGGED_IN_KEY',    '|i|Ux`9<p-h$aFf(qnT:sDO:D1P^wZ$$/Ra@miTJi9G;ddp_<q}6H1)o|a +&JCM');
    2088  *     define('NONCE_KEY',        '%:R{[P|,s.KuMltH5}cI;/k<Gx~j!f0I)m_sIyu+&NJZ)-iO>z7X>QYR0Z_XnZ@|');
    2089  *     define('AUTH_SALT',        'eZyT)-Naw]F8CwA*VaW#q*|.)g@o}||wf~@C-YSt}(dh_r6EbI#A,y|nU2{B#JBW');
    2090  *     define('SECURE_AUTH_SALT', '!=oLUTXh,QW=H `}`L|9/^4-3 STz},T(w}W<I`.JjPi)<Bmf1v,HpGe}T1:Xt7n');
    2091  *     define('LOGGED_IN_SALT',   '+XSqHc;@Q*K_b|Z?NC[3H!!EONbh.n<+=uKR:>*c(u`g~EJBf#8u#R{mUEZrozmm');
    2092  *     define('NONCE_SALT',       'h`GXHhD>SLWVfg1(1(N{;.V!MoE(SfbA_ksP@&`+AycHcAV$+?@3q+rxV{%^VyKT');
    2093  *
    2094  * Salting passwords helps against tools which has stored hashed values of
    2095  * common dictionary strings. The added values makes it harder to crack.
    2096  *
    2097  * @since 2.5.0
    2098  *
    2099  * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
    2100  *
    2101  * @staticvar array $cached_salts
    2102  * @staticvar array $duplicated_keys
    2103  *
    2104  * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
    2105  * @return string Salt value
    2106  */
    2107 function wp_salt( $scheme = 'auth' ) {
    2108     static $cached_salts = array();
    2109     if ( isset( $cached_salts[ $scheme ] ) ) {
    2110         /**
    2111          * Filters the WordPress salt.
    2112          *
    2113          * @since 2.5.0
    2114          *
    2115          * @param string $cached_salt Cached salt for the given scheme.
    2116          * @param string $scheme      Authentication scheme. Values include 'auth',
    2117          *                            'secure_auth', 'logged_in', and 'nonce'.
    2118          */
    2119         return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
    2120     }
    2121 
    2122     static $duplicated_keys;
    2123     if ( null === $duplicated_keys ) {
    2124         $duplicated_keys = array( 'put your unique phrase here' => true );
    2125         foreach ( array( 'AUTH', 'SECURE_AUTH', 'LOGGED_IN', 'NONCE', 'SECRET' ) as $first ) {
    2126             foreach ( array( 'KEY', 'SALT' ) as $second ) {
    2127                 if ( ! defined( "{$first}_{$second}" ) ) {
    2128                     continue;
    2129                 }
    2130                 $value = constant( "{$first}_{$second}" );
    2131                 $duplicated_keys[ $value ] = isset( $duplicated_keys[ $value ] );
    2132             }
    2133         }
    2134     }
    2135 
    2136     $values = array(
    2137         'key' => '',
    2138         'salt' => ''
    2139     );
    2140     if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
    2141         $values['key'] = SECRET_KEY;
    2142     }
    2143     if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
    2144         $values['salt'] = SECRET_SALT;
    2145     }
    2146 
    2147     if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
    2148         foreach ( array( 'key', 'salt' ) as $type ) {
    2149             $const = strtoupper( "{$scheme}_{$type}" );
    2150             if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
    2151                 $values[ $type ] = constant( $const );
    2152             } elseif ( ! $values[ $type ] ) {
    2153                 $values[ $type ] = get_site_option( "{$scheme}_{$type}" );
    2154                 if ( ! $values[ $type ] ) {
    2155                     $values[ $type ] = wp_generate_password( 64, true, true );
    2156                     update_site_option( "{$scheme}_{$type}", $values[ $type ] );
     2069endif;
     2070
     2071if ( ! function_exists( 'wp_create_nonce' ) ) :
     2072    /**
     2073     * Creates a cryptographic token tied to a specific action, user, user session,
     2074     * and window of time.
     2075     *
     2076     * @since 2.0.3
     2077     * @since 4.0.0 Session tokens were integrated with nonce creation
     2078     *
     2079     * @param string|int $action Scalar value to add context to the nonce.
     2080     * @return string The token.
     2081     */
     2082    function wp_create_nonce( $action = -1 ) {
     2083        $user = wp_get_current_user();
     2084        $uid  = (int) $user->ID;
     2085        if ( ! $uid ) {
     2086            /** This filter is documented in wp-includes/pluggable.php */
     2087            $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
     2088        }
     2089
     2090        $token = wp_get_session_token();
     2091        $i     = wp_nonce_tick();
     2092
     2093        return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
     2094    }
     2095endif;
     2096
     2097if ( ! function_exists( 'wp_salt' ) ) :
     2098    /**
     2099     * Get salt to add to hashes.
     2100     *
     2101     * Salts are created using secret keys. Secret keys are located in two places:
     2102     * in the database and in the wp-config.php file. The secret key in the database
     2103     * is randomly generated and will be appended to the secret keys in wp-config.php.
     2104     *
     2105     * The secret keys in wp-config.php should be updated to strong, random keys to maximize
     2106     * security. Below is an example of how the secret key constants are defined.
     2107     * Do not paste this example directly into wp-config.php. Instead, have a
     2108     * {@link https://api.wordpress.org/secret-key/1.1/salt/ secret key created} just
     2109     * for you.
     2110     *
     2111     *     define('AUTH_KEY',         ' Xakm<o xQy rw4EMsLKM-?!T+,PFF})H4lzcW57AF0U@N@< >M%G4Yt>f`z]MON');
     2112     *     define('SECURE_AUTH_KEY',  'LzJ}op]mr|6+![P}Ak:uNdJCJZd>(Hx.-Mh#Tz)pCIU#uGEnfFz|f ;;eU%/U^O~');
     2113     *     define('LOGGED_IN_KEY',    '|i|Ux`9<p-h$aFf(qnT:sDO:D1P^wZ$$/Ra@miTJi9G;ddp_<q}6H1)o|a +&JCM');
     2114     *     define('NONCE_KEY',        '%:R{[P|,s.KuMltH5}cI;/k<Gx~j!f0I)m_sIyu+&NJZ)-iO>z7X>QYR0Z_XnZ@|');
     2115     *     define('AUTH_SALT',        'eZyT)-Naw]F8CwA*VaW#q*|.)g@o}||wf~@C-YSt}(dh_r6EbI#A,y|nU2{B#JBW');
     2116     *     define('SECURE_AUTH_SALT', '!=oLUTXh,QW=H `}`L|9/^4-3 STz},T(w}W<I`.JjPi)<Bmf1v,HpGe}T1:Xt7n');
     2117     *     define('LOGGED_IN_SALT',   '+XSqHc;@Q*K_b|Z?NC[3H!!EONbh.n<+=uKR:>*c(u`g~EJBf#8u#R{mUEZrozmm');
     2118     *     define('NONCE_SALT',       'h`GXHhD>SLWVfg1(1(N{;.V!MoE(SfbA_ksP@&`+AycHcAV$+?@3q+rxV{%^VyKT');
     2119     *
     2120     * Salting passwords helps against tools which has stored hashed values of
     2121     * common dictionary strings. The added values makes it harder to crack.
     2122     *
     2123     * @since 2.5.0
     2124     *
     2125     * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
     2126     *
     2127     * @staticvar array $cached_salts
     2128     * @staticvar array $duplicated_keys
     2129     *
     2130     * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
     2131     * @return string Salt value
     2132     */
     2133    function wp_salt( $scheme = 'auth' ) {
     2134        static $cached_salts = array();
     2135        if ( isset( $cached_salts[ $scheme ] ) ) {
     2136            /**
     2137             * Filters the WordPress salt.
     2138             *
     2139             * @since 2.5.0
     2140             *
     2141             * @param string $cached_salt Cached salt for the given scheme.
     2142             * @param string $scheme      Authentication scheme. Values include 'auth',
     2143             *                            'secure_auth', 'logged_in', and 'nonce'.
     2144             */
     2145            return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
     2146        }
     2147
     2148        static $duplicated_keys;
     2149        if ( null === $duplicated_keys ) {
     2150            $duplicated_keys = array( 'put your unique phrase here' => true );
     2151            foreach ( array( 'AUTH', 'SECURE_AUTH', 'LOGGED_IN', 'NONCE', 'SECRET' ) as $first ) {
     2152                foreach ( array( 'KEY', 'SALT' ) as $second ) {
     2153                    if ( ! defined( "{$first}_{$second}" ) ) {
     2154                        continue;
     2155                    }
     2156                    $value                     = constant( "{$first}_{$second}" );
     2157                    $duplicated_keys[ $value ] = isset( $duplicated_keys[ $value ] );
    21572158                }
    21582159            }
    21592160        }
    2160     } else {
    2161         if ( ! $values['key'] ) {
    2162             $values['key'] = get_site_option( 'secret_key' );
     2161
     2162        $values = array(
     2163            'key'  => '',
     2164            'salt' => '',
     2165        );
     2166        if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
     2167            $values['key'] = SECRET_KEY;
     2168        }
     2169        if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
     2170            $values['salt'] = SECRET_SALT;
     2171        }
     2172
     2173        if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
     2174            foreach ( array( 'key', 'salt' ) as $type ) {
     2175                $const = strtoupper( "{$scheme}_{$type}" );
     2176                if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
     2177                    $values[ $type ] = constant( $const );
     2178                } elseif ( ! $values[ $type ] ) {
     2179                    $values[ $type ] = get_site_option( "{$scheme}_{$type}" );
     2180                    if ( ! $values[ $type ] ) {
     2181                        $values[ $type ] = wp_generate_password( 64, true, true );
     2182                        update_site_option( "{$scheme}_{$type}", $values[ $type ] );
     2183                    }
     2184                }
     2185            }
     2186        } else {
    21632187            if ( ! $values['key'] ) {
    2164                 $values['key'] = wp_generate_password( 64, true, true );
    2165                 update_site_option( 'secret_key', $values['key'] );
     2188                $values['key'] = get_site_option( 'secret_key' );
     2189                if ( ! $values['key'] ) {
     2190                    $values['key'] = wp_generate_password( 64, true, true );
     2191                    update_site_option( 'secret_key', $values['key'] );
     2192                }
    21662193            }
    2167         }
    2168         $values['salt'] = hash_hmac( 'md5', $scheme, $values['key'] );
    2169     }
    2170 
    2171     $cached_salts[ $scheme ] = $values['key'] . $values['salt'];
    2172 
    2173     /** This filter is documented in wp-includes/pluggable.php */
    2174     return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
    2175 }
    2176 endif;
    2177 
    2178 if ( !function_exists('wp_hash') ) :
    2179 /**
    2180  * Get hash of given string.
    2181  *
    2182  * @since 2.0.3
    2183  *
    2184  * @param string $data   Plain text to hash
    2185  * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
    2186  * @return string Hash of $data
    2187  */
    2188 function wp_hash($data, $scheme = 'auth') {
    2189     $salt = wp_salt($scheme);
    2190 
    2191     return hash_hmac('md5', $data, $salt);
    2192 }
    2193 endif;
    2194 
    2195 if ( !function_exists('wp_hash_password') ) :
    2196 /**
    2197  * Create a hash (encrypt) of a plain text password.
    2198  *
    2199  * For integration with other applications, this function can be overwritten to
    2200  * instead use the other package password checking algorithm.
    2201  *
    2202  * @since 2.5.0
    2203  *
    2204  * @global PasswordHash $wp_hasher PHPass object
    2205  *
    2206  * @param string $password Plain text user password to hash
    2207  * @return string The hash string of the password
    2208  */
    2209 function wp_hash_password($password) {
    2210     global $wp_hasher;
    2211 
    2212     if ( empty($wp_hasher) ) {
    2213         require_once( ABSPATH . WPINC . '/class-phpass.php');
    2214         // By default, use the portable hash from phpass
    2215         $wp_hasher = new PasswordHash(8, true);
    2216     }
    2217 
    2218     return $wp_hasher->HashPassword( trim( $password ) );
    2219 }
    2220 endif;
    2221 
    2222 if ( !function_exists('wp_check_password') ) :
    2223 /**
    2224  * Checks the plaintext password against the encrypted Password.
    2225  *
    2226  * Maintains compatibility between old version and the new cookie authentication
    2227  * protocol using PHPass library. The $hash parameter is the encrypted password
    2228  * and the function compares the plain text password when encrypted similarly
    2229  * against the already encrypted password to see if they match.
    2230  *
    2231  * For integration with other applications, this function can be overwritten to
    2232  * instead use the other package password checking algorithm.
    2233  *
    2234  * @since 2.5.0
    2235  *
    2236  * @global PasswordHash $wp_hasher PHPass object used for checking the password
    2237  *  against the $hash + $password
    2238  * @uses PasswordHash::CheckPassword
    2239  *
    2240  * @param string     $password Plaintext user's password
    2241  * @param string     $hash     Hash of the user's password to check against.
    2242  * @param string|int $user_id  Optional. User ID.
    2243  * @return bool False, if the $password does not match the hashed password
    2244  */
    2245 function wp_check_password($password, $hash, $user_id = '') {
    2246     global $wp_hasher;
    2247 
    2248     // If the hash is still md5...
    2249     if ( strlen($hash) <= 32 ) {
    2250         $check = hash_equals( $hash, md5( $password ) );
    2251         if ( $check && $user_id ) {
    2252             // Rehash using new hash.
    2253             wp_set_password($password, $user_id);
    2254             $hash = wp_hash_password($password);
    2255         }
    2256 
    2257         /**
    2258          * Filters whether the plaintext password matches the encrypted password.
    2259          *
    2260          * @since 2.5.0
    2261          *
    2262          * @param bool       $check    Whether the passwords match.
    2263          * @param string     $password The plaintext password.
    2264          * @param string     $hash     The hashed password.
    2265          * @param string|int $user_id  User ID. Can be empty.
    2266          */
     2194            $values['salt'] = hash_hmac( 'md5', $scheme, $values['key'] );
     2195        }
     2196
     2197        $cached_salts[ $scheme ] = $values['key'] . $values['salt'];
     2198
     2199        /** This filter is documented in wp-includes/pluggable.php */
     2200        return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
     2201    }
     2202endif;
     2203
     2204if ( ! function_exists( 'wp_hash' ) ) :
     2205    /**
     2206     * Get hash of given string.
     2207     *
     2208     * @since 2.0.3
     2209     *
     2210     * @param string $data   Plain text to hash
     2211     * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
     2212     * @return string Hash of $data
     2213     */
     2214    function wp_hash( $data, $scheme = 'auth' ) {
     2215        $salt = wp_salt( $scheme );
     2216
     2217        return hash_hmac( 'md5', $data, $salt );
     2218    }
     2219endif;
     2220
     2221if ( ! function_exists( 'wp_hash_password' ) ) :
     2222    /**
     2223     * Create a hash (encrypt) of a plain text password.
     2224     *
     2225     * For integration with other applications, this function can be overwritten to
     2226     * instead use the other package password checking algorithm.
     2227     *
     2228     * @since 2.5.0
     2229     *
     2230     * @global PasswordHash $wp_hasher PHPass object
     2231     *
     2232     * @param string $password Plain text user password to hash
     2233     * @return string The hash string of the password
     2234     */
     2235    function wp_hash_password( $password ) {
     2236        global $wp_hasher;
     2237
     2238        if ( empty( $wp_hasher ) ) {
     2239            require_once( ABSPATH . WPINC . '/class-phpass.php' );
     2240            // By default, use the portable hash from phpass
     2241            $wp_hasher = new PasswordHash( 8, true );
     2242        }
     2243
     2244        return $wp_hasher->HashPassword( trim( $password ) );
     2245    }
     2246endif;
     2247
     2248if ( ! function_exists( 'wp_check_password' ) ) :
     2249    /**
     2250     * Checks the plaintext password against the encrypted Password.
     2251     *
     2252     * Maintains compatibility between old version and the new cookie authentication
     2253     * protocol using PHPass library. The $hash parameter is the encrypted password
     2254     * and the function compares the plain text password when encrypted similarly
     2255     * against the already encrypted password to see if they match.
     2256     *
     2257     * For integration with other applications, this function can be overwritten to
     2258     * instead use the other package password checking algorithm.
     2259     *
     2260     * @since 2.5.0
     2261     *
     2262     * @global PasswordHash $wp_hasher PHPass object used for checking the password
     2263     *  against the $hash + $password
     2264     * @uses PasswordHash::CheckPassword
     2265     *
     2266     * @param string     $password Plaintext user's password
     2267     * @param string     $hash     Hash of the user's password to check against.
     2268     * @param string|int $user_id  Optional. User ID.
     2269     * @return bool False, if the $password does not match the hashed password
     2270     */
     2271    function wp_check_password( $password, $hash, $user_id = '' ) {
     2272        global $wp_hasher;
     2273
     2274        // If the hash is still md5...
     2275        if ( strlen( $hash ) <= 32 ) {
     2276            $check = hash_equals( $hash, md5( $password ) );
     2277            if ( $check && $user_id ) {
     2278                // Rehash using new hash.
     2279                wp_set_password( $password, $user_id );
     2280                $hash = wp_hash_password( $password );
     2281            }
     2282
     2283            /**
     2284             * Filters whether the plaintext password matches the encrypted password.
     2285             *
     2286             * @since 2.5.0
     2287             *
     2288             * @param bool       $check    Whether the passwords match.
     2289             * @param string     $password The plaintext password.
     2290             * @param string     $hash     The hashed password.
     2291             * @param string|int $user_id  User ID. Can be empty.
     2292             */
     2293            return apply_filters( 'check_password', $check, $password, $hash, $user_id );
     2294        }
     2295
     2296        // If the stored hash is longer than an MD5, presume the
     2297        // new style phpass portable hash.
     2298        if ( empty( $wp_hasher ) ) {
     2299            require_once( ABSPATH . WPINC . '/class-phpass.php' );
     2300            // By default, use the portable hash from phpass
     2301            $wp_hasher = new PasswordHash( 8, true );
     2302        }
     2303
     2304        $check = $wp_hasher->CheckPassword( $password, $hash );
     2305
     2306        /** This filter is documented in wp-includes/pluggable.php */
    22672307        return apply_filters( 'check_password', $check, $password, $hash, $user_id );
    22682308    }
    2269 
    2270     // If the stored hash is longer than an MD5, presume the
    2271     // new style phpass portable hash.
    2272     if ( empty($wp_hasher) ) {
    2273         require_once( ABSPATH . WPINC . '/class-phpass.php');
    2274         // By default, use the portable hash from phpass
    2275         $wp_hasher = new PasswordHash(8, true);
    2276     }
    2277 
    2278     $check = $wp_hasher->CheckPassword($password, $hash);
    2279 
    2280     /** This filter is documented in wp-includes/pluggable.php */
    2281     return apply_filters( 'check_password', $check, $password, $hash, $user_id );
    2282 }
    2283 endif;
    2284 
    2285 if ( !function_exists('wp_generate_password') ) :
    2286 /**
    2287  * Generates a random password drawn from the defined set of characters.
    2288  *
    2289  * @since 2.5.0
    2290  *
    2291  * @param int  $length              Optional. The length of password to generate. Default 12.
    2292  * @param bool $special_chars       Optional. Whether to include standard special characters.
    2293  *                                  Default true.
    2294  * @param bool $extra_special_chars Optional. Whether to include other special characters.
    2295  *                                  Used when generating secret keys and salts. Default false.
    2296  * @return string The random password.
    2297  */
    2298 function wp_generate_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
    2299     $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    2300     if ( $special_chars )
    2301         $chars .= '!@#$%^&*()';
    2302     if ( $extra_special_chars )
    2303         $chars .= '-_ []{}<>~`+=,.;:/?|';
    2304 
    2305     $password = '';
    2306     for ( $i = 0; $i < $length; $i++ ) {
    2307         $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
    2308     }
    2309 
    2310     /**
    2311      * Filters the randomly-generated password.
    2312      *
    2313      * @since 3.0.0
    2314      *
    2315      * @param string $password The generated password.
    2316      */
    2317     return apply_filters( 'random_password', $password );
    2318 }
    2319 endif;
    2320 
    2321 if ( !function_exists('wp_rand') ) :
    2322 /**
    2323  * Generates a random number
    2324  *
    2325  * @since 2.6.2
    2326  * @since 4.4.0 Uses PHP7 random_int() or the random_compat library if available.
    2327  *
    2328  * @global string $rnd_value
    2329  * @staticvar string $seed
    2330  * @staticvar bool $external_rand_source_available
    2331  *
    2332  * @param int $min Lower limit for the generated number
    2333  * @param int $max Upper limit for the generated number
    2334  * @return int A random number between min and max
    2335  */
    2336 function wp_rand( $min = 0, $max = 0 ) {
    2337     global $rnd_value;
    2338 
    2339     // 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.
    2340     $max_random_number = 3000000000 === 2147483647 ? (float) "4294967295" : 4294967295; // 4294967295 = 0xffffffff
    2341 
    2342     // We only handle Ints, floats are truncated to their integer value.
    2343     $min = (int) $min;
    2344     $max = (int) $max;
    2345 
    2346     // Use PHP's CSPRNG, or a compatible method
    2347     static $use_random_int_functionality = true;
    2348     if ( $use_random_int_functionality ) {
    2349         try {
    2350             $_max = ( 0 != $max ) ? $max : $max_random_number;
    2351             // wp_rand() can accept arguments in either order, PHP cannot.
    2352             $_max = max( $min, $_max );
    2353             $_min = min( $min, $_max );
    2354             $val = random_int( $_min, $_max );
    2355             if ( false !== $val ) {
    2356                 return absint( $val );
    2357             } else {
     2309endif;
     2310
     2311if ( ! function_exists( 'wp_generate_password' ) ) :
     2312    /**
     2313     * Generates a random password drawn from the defined set of characters.
     2314     *
     2315     * @since 2.5.0
     2316     *
     2317     * @param int  $length              Optional. The length of password to generate. Default 12.
     2318     * @param bool $special_chars       Optional. Whether to include standard special characters.
     2319     *                                  Default true.
     2320     * @param bool $extra_special_chars Optional. Whether to include other special characters.
     2321     *                                  Used when generating secret keys and salts. Default false.
     2322     * @return string The random password.
     2323     */
     2324    function wp_generate_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
     2325        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
     2326        if ( $special_chars ) {
     2327            $chars .= '!@#$%^&*()';
     2328        }
     2329        if ( $extra_special_chars ) {
     2330            $chars .= '-_ []{}<>~`+=,.;:/?|';
     2331        }
     2332
     2333        $password = '';
     2334        for ( $i = 0; $i < $length; $i++ ) {
     2335            $password .= substr( $chars, wp_rand( 0, strlen( $chars ) - 1 ), 1 );
     2336        }
     2337
     2338        /**
     2339         * Filters the randomly-generated password.
     2340         *
     2341         * @since 3.0.0
     2342         *
     2343         * @param string $password The generated password.
     2344         */
     2345        return apply_filters( 'random_password', $password );
     2346    }
     2347endif;
     2348
     2349if ( ! function_exists( 'wp_rand' ) ) :
     2350    /**
     2351     * Generates a random number
     2352     *
     2353     * @since 2.6.2
     2354     * @since 4.4.0 Uses PHP7 random_int() or the random_compat library if available.
     2355     *
     2356     * @global string $rnd_value
     2357     * @staticvar string $seed
     2358     * @staticvar bool $external_rand_source_available
     2359     *
     2360     * @param int $min Lower limit for the generated number
     2361     * @param int $max Upper limit for the generated number
     2362     * @return int A random number between min and max
     2363     */
     2364    function wp_rand( $min = 0, $max = 0 ) {
     2365        global $rnd_value;
     2366
     2367        // 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.
     2368        $max_random_number = 3000000000 === 2147483647 ? (float) '4294967295' : 4294967295; // 4294967295 = 0xffffffff
     2369
     2370        // We only handle Ints, floats are truncated to their integer value.
     2371        $min = (int) $min;
     2372        $max = (int) $max;
     2373
     2374        // Use PHP's CSPRNG, or a compatible method
     2375        static $use_random_int_functionality = true;
     2376        if ( $use_random_int_functionality ) {
     2377            try {
     2378                $_max = ( 0 != $max ) ? $max : $max_random_number;
     2379                // wp_rand() can accept arguments in either order, PHP cannot.
     2380                $_max = max( $min, $_max );
     2381                $_min = min( $min, $_max );
     2382                $val  = random_int( $_min, $_max );
     2383                if ( false !== $val ) {
     2384                    return absint( $val );
     2385                } else {
     2386                    $use_random_int_functionality = false;
     2387                }
     2388            } catch ( Error $e ) {
     2389                $use_random_int_functionality = false;
     2390            } catch ( Exception $e ) {
    23582391                $use_random_int_functionality = false;
    23592392            }
    2360         } catch ( Error $e ) {
    2361             $use_random_int_functionality = false;
    2362         } catch ( Exception $e ) {
    2363             $use_random_int_functionality = false;
    2364         }
    2365     }
    2366 
    2367     // Reset $rnd_value after 14 uses
    2368     // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
    2369     if ( strlen($rnd_value) < 8 ) {
    2370         if ( defined( 'WP_SETUP_CONFIG' ) )
    2371             static $seed = '';
    2372         else
    2373             $seed = get_transient('random_seed');
    2374         $rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
    2375         $rnd_value .= sha1($rnd_value);
    2376         $rnd_value .= sha1($rnd_value . $seed);
    2377         $seed = md5($seed . $rnd_value);
    2378         if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
    2379             set_transient( 'random_seed', $seed );
    2380         }
    2381     }
    2382 
    2383     // Take the first 8 digits for our value
    2384     $value = substr($rnd_value, 0, 8);
    2385 
    2386     // Strip the first eight, leaving the remainder for the next call to wp_rand().
    2387     $rnd_value = substr($rnd_value, 8);
    2388 
    2389     $value = abs(hexdec($value));
    2390 
    2391     // Reduce the value to be within the min - max range
    2392     if ( $max != 0 )
    2393         $value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
    2394 
    2395     return abs(intval($value));
    2396 }
    2397 endif;
    2398 
    2399 if ( !function_exists('wp_set_password') ) :
    2400 /**
    2401  * Updates the user's password with a new encrypted one.
    2402  *
    2403  * For integration with other applications, this function can be overwritten to
    2404  * instead use the other package password checking algorithm.
    2405  *
    2406  * Please note: This function should be used sparingly and is really only meant for single-time
    2407  * application. Leveraging this improperly in a plugin or theme could result in an endless loop
    2408  * of password resets if precautions are not taken to ensure it does not execute on every page load.
    2409  *
    2410  * @since 2.5.0
    2411  *
    2412  * @global wpdb $wpdb WordPress database abstraction object.
    2413  *
    2414  * @param string $password The plaintext new user password
    2415  * @param int    $user_id  User ID
    2416  */
    2417 function wp_set_password( $password, $user_id ) {
    2418     global $wpdb;
    2419 
    2420     $hash = wp_hash_password( $password );
    2421     $wpdb->update($wpdb->users, array('user_pass' => $hash, 'user_activation_key' => ''), array('ID' => $user_id) );
    2422 
    2423     wp_cache_delete($user_id, 'users');
    2424 }
    2425 endif;
    2426 
    2427 if ( !function_exists( 'get_avatar' ) ) :
    2428 /**
    2429  * Retrieve the avatar `<img>` tag for a user, email address, MD5 hash, comment, or post.
    2430  *
    2431  * @since 2.5.0
    2432  * @since 4.2.0 Optional `$args` parameter added.
    2433  *
    2434  * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
    2435  *                           user email, WP_User object, WP_Post object, or WP_Comment object.
    2436  * @param int    $size       Optional. Height and width of the avatar image file in pixels. Default 96.
    2437  * @param string $default    Optional. URL for the default image or a default type. Accepts '404'
    2438  *                           (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
    2439  *                           (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
    2440  *                           'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
    2441  *                           or 'gravatar_default' (the Gravatar logo). Default is the value of the
    2442  *                           'avatar_default' option, with a fallback of 'mystery'.
    2443  * @param string $alt        Optional. Alternative text to use in &lt;img&gt; tag. Default empty.
    2444  * @param array  $args       {
    2445  *     Optional. Extra arguments to retrieve the avatar.
    2446  *
    2447  *     @type int          $height        Display height of the avatar in pixels. Defaults to $size.
    2448  *     @type int          $width         Display width of the avatar in pixels. Defaults to $size.
    2449  *     @type bool         $force_default Whether to always show the default image, never the Gravatar. Default false.
    2450  *     @type string       $rating        What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are
    2451  *                                       judged in that order. Default is the value of the 'avatar_rating' option.
    2452  *     @type string       $scheme        URL scheme to use. See set_url_scheme() for accepted values.
    2453  *                                       Default null.
    2454  *     @type array|string $class         Array or string of additional classes to add to the &lt;img&gt; element.
    2455  *                                       Default null.
    2456  *     @type bool         $force_display Whether to always show the avatar - ignores the show_avatars option.
    2457  *                                       Default false.
    2458  *     @type string       $extra_attr    HTML attributes to insert in the IMG element. Is not sanitized. Default empty.
    2459  * }
    2460  * @return false|string `<img>` tag for the user's avatar. False on failure.
    2461  */
    2462 function get_avatar( $id_or_email, $size = 96, $default = '', $alt = '', $args = null ) {
    2463     $defaults = array(
    2464         // get_avatar_data() args.
    2465         'size'          => 96,
    2466         'height'        => null,
    2467         'width'         => null,
    2468         'default'       => get_option( 'avatar_default', 'mystery' ),
    2469         'force_default' => false,
    2470         'rating'        => get_option( 'avatar_rating' ),
    2471         'scheme'        => null,
    2472         'alt'           => '',
    2473         'class'         => null,
    2474         'force_display' => false,
    2475         'extra_attr'    => '',
    2476     );
    2477 
    2478     if ( empty( $args ) ) {
    2479         $args = array();
    2480     }
    2481 
    2482     $args['size']    = (int) $size;
    2483     $args['default'] = $default;
    2484     $args['alt']     = $alt;
    2485 
    2486     $args = wp_parse_args( $args, $defaults );
    2487 
    2488     if ( empty( $args['height'] ) ) {
    2489         $args['height'] = $args['size'];
    2490     }
    2491     if ( empty( $args['width'] ) ) {
    2492         $args['width'] = $args['size'];
    2493     }
    2494 
    2495     if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
    2496         $id_or_email = get_comment( $id_or_email );
    2497     }
    2498 
    2499     /**
    2500      * Filters whether to retrieve the avatar URL early.
    2501      *
    2502      * Passing a non-null value will effectively short-circuit get_avatar(), passing
    2503      * the value through the {@see 'get_avatar'} filter and returning early.
    2504      *
    2505      * @since 4.2.0
    2506      *
    2507      * @param string $avatar      HTML for the user's avatar. Default null.
    2508      * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
    2509      *                            user email, WP_User object, WP_Post object, or WP_Comment object.
    2510      * @param array  $args        Arguments passed to get_avatar_url(), after processing.
    2511      */
    2512     $avatar = apply_filters( 'pre_get_avatar', null, $id_or_email, $args );
    2513 
    2514     if ( ! is_null( $avatar ) ) {
    2515         /** This filter is documented in wp-includes/pluggable.php */
     2393        }
     2394
     2395        // Reset $rnd_value after 14 uses
     2396        // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
     2397        if ( strlen( $rnd_value ) < 8 ) {
     2398            if ( defined( 'WP_SETUP_CONFIG' ) ) {
     2399                static $seed = '';
     2400            } else {
     2401                $seed = get_transient( 'random_seed' );
     2402            }
     2403            $rnd_value  = md5( uniqid( microtime() . mt_rand(), true ) . $seed );
     2404            $rnd_value .= sha1( $rnd_value );
     2405            $rnd_value .= sha1( $rnd_value . $seed );
     2406            $seed       = md5( $seed . $rnd_value );
     2407            if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
     2408                set_transient( 'random_seed', $seed );
     2409            }
     2410        }
     2411
     2412        // Take the first 8 digits for our value
     2413        $value = substr( $rnd_value, 0, 8 );
     2414
     2415        // Strip the first eight, leaving the remainder for the next call to wp_rand().
     2416        $rnd_value = substr( $rnd_value, 8 );
     2417
     2418        $value = abs( hexdec( $value ) );
     2419
     2420        // Reduce the value to be within the min - max range
     2421        if ( $max != 0 ) {
     2422            $value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
     2423        }
     2424
     2425        return abs( intval( $value ) );
     2426    }
     2427endif;
     2428
     2429if ( ! function_exists( 'wp_set_password' ) ) :
     2430    /**
     2431     * Updates the user's password with a new encrypted one.
     2432     *
     2433     * For integration with other applications, this function can be overwritten to
     2434     * instead use the other package password checking algorithm.
     2435     *
     2436     * Please note: This function should be used sparingly and is really only meant for single-time
     2437     * application. Leveraging this improperly in a plugin or theme could result in an endless loop
     2438     * of password resets if precautions are not taken to ensure it does not execute on every page load.
     2439     *
     2440     * @since 2.5.0
     2441     *
     2442     * @global wpdb $wpdb WordPress database abstraction object.
     2443     *
     2444     * @param string $password The plaintext new user password
     2445     * @param int    $user_id  User ID
     2446     */
     2447    function wp_set_password( $password, $user_id ) {
     2448        global $wpdb;
     2449
     2450        $hash = wp_hash_password( $password );
     2451        $wpdb->update(
     2452            $wpdb->users, array(
     2453                'user_pass'           => $hash,
     2454                'user_activation_key' => '',
     2455            ), array( 'ID' => $user_id )
     2456        );
     2457
     2458        wp_cache_delete( $user_id, 'users' );
     2459    }
     2460endif;
     2461
     2462if ( ! function_exists( 'get_avatar' ) ) :
     2463    /**
     2464     * Retrieve the avatar `<img>` tag for a user, email address, MD5 hash, comment, or post.
     2465     *
     2466     * @since 2.5.0
     2467     * @since 4.2.0 Optional `$args` parameter added.
     2468     *
     2469     * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
     2470     *                           user email, WP_User object, WP_Post object, or WP_Comment object.
     2471     * @param int    $size       Optional. Height and width of the avatar image file in pixels. Default 96.
     2472     * @param string $default    Optional. URL for the default image or a default type. Accepts '404'
     2473     *                           (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
     2474     *                           (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
     2475     *                           'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
     2476     *                           or 'gravatar_default' (the Gravatar logo). Default is the value of the
     2477     *                           'avatar_default' option, with a fallback of 'mystery'.
     2478     * @param string $alt        Optional. Alternative text to use in &lt;img&gt; tag. Default empty.
     2479     * @param array  $args       {
     2480     *     Optional. Extra arguments to retrieve the avatar.
     2481     *
     2482     *     @type int          $height        Display height of the avatar in pixels. Defaults to $size.
     2483     *     @type int          $width         Display width of the avatar in pixels. Defaults to $size.
     2484     *     @type bool         $force_default Whether to always show the default image, never the Gravatar. Default false.
     2485     *     @type string       $rating        What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are
     2486     *                                       judged in that order. Default is the value of the 'avatar_rating' option.
     2487     *     @type string       $scheme        URL scheme to use. See set_url_scheme() for accepted values.
     2488     *                                       Default null.
     2489     *     @type array|string $class         Array or string of additional classes to add to the &lt;img&gt; element.
     2490     *                                       Default null.
     2491     *     @type bool         $force_display Whether to always show the avatar - ignores the show_avatars option.
     2492     *                                       Default false.
     2493     *     @type string       $extra_attr    HTML attributes to insert in the IMG element. Is not sanitized. Default empty.
     2494     * }
     2495     * @return false|string `<img>` tag for the user's avatar. False on failure.
     2496     */
     2497    function get_avatar( $id_or_email, $size = 96, $default = '', $alt = '', $args = null ) {
     2498        $defaults = array(
     2499            // get_avatar_data() args.
     2500            'size'          => 96,
     2501            'height'        => null,
     2502            'width'         => null,
     2503            'default'       => get_option( 'avatar_default', 'mystery' ),
     2504            'force_default' => false,
     2505            'rating'        => get_option( 'avatar_rating' ),
     2506            'scheme'        => null,
     2507            'alt'           => '',
     2508            'class'         => null,
     2509            'force_display' => false,
     2510            'extra_attr'    => '',
     2511        );
     2512
     2513        if ( empty( $args ) ) {
     2514            $args = array();
     2515        }
     2516
     2517        $args['size']    = (int) $size;
     2518        $args['default'] = $default;
     2519        $args['alt']     = $alt;
     2520
     2521        $args = wp_parse_args( $args, $defaults );
     2522
     2523        if ( empty( $args['height'] ) ) {
     2524            $args['height'] = $args['size'];
     2525        }
     2526        if ( empty( $args['width'] ) ) {
     2527            $args['width'] = $args['size'];
     2528        }
     2529
     2530        if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
     2531            $id_or_email = get_comment( $id_or_email );
     2532        }
     2533
     2534        /**
     2535         * Filters whether to retrieve the avatar URL early.
     2536         *
     2537         * Passing a non-null value will effectively short-circuit get_avatar(), passing
     2538         * the value through the {@see 'get_avatar'} filter and returning early.
     2539         *
     2540         * @since 4.2.0
     2541         *
     2542         * @param string $avatar      HTML for the user's avatar. Default null.
     2543         * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
     2544         *                            user email, WP_User object, WP_Post object, or WP_Comment object.
     2545         * @param array  $args        Arguments passed to get_avatar_url(), after processing.
     2546         */
     2547        $avatar = apply_filters( 'pre_get_avatar', null, $id_or_email, $args );
     2548
     2549        if ( ! is_null( $avatar ) ) {
     2550            /** This filter is documented in wp-includes/pluggable.php */
     2551            return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
     2552        }
     2553
     2554        if ( ! $args['force_display'] && ! get_option( 'show_avatars' ) ) {
     2555            return false;
     2556        }
     2557
     2558        $url2x = get_avatar_url( $id_or_email, array_merge( $args, array( 'size' => $args['size'] * 2 ) ) );
     2559
     2560        $args = get_avatar_data( $id_or_email, $args );
     2561
     2562        $url = $args['url'];
     2563
     2564        if ( ! $url || is_wp_error( $url ) ) {
     2565            return false;
     2566        }
     2567
     2568        $class = array( 'avatar', 'avatar-' . (int) $args['size'], 'photo' );
     2569
     2570        if ( ! $args['found_avatar'] || $args['force_default'] ) {
     2571            $class[] = 'avatar-default';
     2572        }
     2573
     2574        if ( $args['class'] ) {
     2575            if ( is_array( $args['class'] ) ) {
     2576                $class = array_merge( $class, $args['class'] );
     2577            } else {
     2578                $class[] = $args['class'];
     2579            }
     2580        }
     2581
     2582        $avatar = sprintf(
     2583            "<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
     2584            esc_attr( $args['alt'] ),
     2585            esc_url( $url ),
     2586            esc_url( $url2x ) . ' 2x',
     2587            esc_attr( join( ' ', $class ) ),
     2588            (int) $args['height'],
     2589            (int) $args['width'],
     2590            $args['extra_attr']
     2591        );
     2592
     2593        /**
     2594         * Filters the avatar to retrieve.
     2595         *
     2596         * @since 2.5.0
     2597         * @since 4.2.0 The `$args` parameter was added.
     2598         *
     2599         * @param string $avatar      &lt;img&gt; tag for the user's avatar.
     2600         * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
     2601         *                            user email, WP_User object, WP_Post object, or WP_Comment object.
     2602         * @param int    $size        Square avatar width and height in pixels to retrieve.
     2603         * @param string $default     URL for the default image or a default type. Accepts '404', 'retro', 'monsterid',
     2604         *                            'wavatar', 'indenticon','mystery' (or 'mm', or 'mysteryman'), 'blank', or 'gravatar_default'.
     2605         *                            Default is the value of the 'avatar_default' option, with a fallback of 'mystery'.
     2606         * @param string $alt         Alternative text to use in the avatar image tag. Default empty.
     2607         * @param array  $args        Arguments passed to get_avatar_data(), after processing.
     2608         */
    25162609        return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
    25172610    }
    2518 
    2519     if ( ! $args['force_display'] && ! get_option( 'show_avatars' ) ) {
    2520         return false;
    2521     }
    2522 
    2523     $url2x = get_avatar_url( $id_or_email, array_merge( $args, array( 'size' => $args['size'] * 2 ) ) );
    2524 
    2525     $args = get_avatar_data( $id_or_email, $args );
    2526 
    2527     $url = $args['url'];
    2528 
    2529     if ( ! $url || is_wp_error( $url ) ) {
    2530         return false;
    2531     }
    2532 
    2533     $class = array( 'avatar', 'avatar-' . (int) $args['size'], 'photo' );
    2534 
    2535     if ( ! $args['found_avatar'] || $args['force_default'] ) {
    2536         $class[] = 'avatar-default';
    2537     }
    2538 
    2539     if ( $args['class'] ) {
    2540         if ( is_array( $args['class'] ) ) {
    2541             $class = array_merge( $class, $args['class'] );
     2611endif;
     2612
     2613if ( ! function_exists( 'wp_text_diff' ) ) :
     2614    /**
     2615     * Displays a human readable HTML representation of the difference between two strings.
     2616     *
     2617     * The Diff is available for getting the changes between versions. The output is
     2618     * HTML, so the primary use is for displaying the changes. If the two strings
     2619     * are equivalent, then an empty string will be returned.
     2620     *
     2621     * The arguments supported and can be changed are listed below.
     2622     *
     2623     * 'title' : Default is an empty string. Titles the diff in a manner compatible
     2624     *      with the output.
     2625     * 'title_left' : Default is an empty string. Change the HTML to the left of the
     2626     *      title.
     2627     * 'title_right' : Default is an empty string. Change the HTML to the right of
     2628     *      the title.
     2629     *
     2630     * @since 2.6.0
     2631     *
     2632     * @see wp_parse_args() Used to change defaults to user defined settings.
     2633     * @uses Text_Diff
     2634     * @uses WP_Text_Diff_Renderer_Table
     2635     *
     2636     * @param string       $left_string  "old" (left) version of string
     2637     * @param string       $right_string "new" (right) version of string
     2638     * @param string|array $args         Optional. Change 'title', 'title_left', and 'title_right' defaults.
     2639     * @return string Empty string if strings are equivalent or HTML with differences.
     2640     */
     2641    function wp_text_diff( $left_string, $right_string, $args = null ) {
     2642        $defaults = array(
     2643            'title'       => '',
     2644            'title_left'  => '',
     2645            'title_right' => '',
     2646        );
     2647        $args     = wp_parse_args( $args, $defaults );
     2648
     2649        if ( ! class_exists( 'WP_Text_Diff_Renderer_Table', false ) ) {
     2650            require( ABSPATH . WPINC . '/wp-diff.php' );
     2651        }
     2652
     2653        $left_string  = normalize_whitespace( $left_string );
     2654        $right_string = normalize_whitespace( $right_string );
     2655
     2656        $left_lines  = explode( "\n", $left_string );
     2657        $right_lines = explode( "\n", $right_string );
     2658        $text_diff   = new Text_Diff( $left_lines, $right_lines );
     2659        $renderer    = new WP_Text_Diff_Renderer_Table( $args );
     2660        $diff        = $renderer->render( $text_diff );
     2661
     2662        if ( ! $diff ) {
     2663            return '';
     2664        }
     2665
     2666        $r = "<table class='diff'>\n";
     2667
     2668        if ( ! empty( $args['show_split_view'] ) ) {
     2669            $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
    25422670        } else {
    2543             $class[] = $args['class'];
    2544         }
    2545     }
    2546 
    2547     $avatar = sprintf(
    2548         "<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
    2549         esc_attr( $args['alt'] ),
    2550         esc_url( $url ),
    2551         esc_url( $url2x ) . ' 2x',
    2552         esc_attr( join( ' ', $class ) ),
    2553         (int) $args['height'],
    2554         (int) $args['width'],
    2555         $args['extra_attr']
    2556     );
    2557 
    2558     /**
    2559      * Filters the avatar to retrieve.
    2560      *
    2561      * @since 2.5.0
    2562      * @since 4.2.0 The `$args` parameter was added.
    2563      *
    2564      * @param string $avatar      &lt;img&gt; tag for the user's avatar.
    2565      * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
    2566      *                            user email, WP_User object, WP_Post object, or WP_Comment object.
    2567      * @param int    $size        Square avatar width and height in pixels to retrieve.
    2568      * @param string $default     URL for the default image or a default type. Accepts '404', 'retro', 'monsterid',
    2569      *                            'wavatar', 'indenticon','mystery' (or 'mm', or 'mysteryman'), 'blank', or 'gravatar_default'.
    2570      *                            Default is the value of the 'avatar_default' option, with a fallback of 'mystery'.
    2571      * @param string $alt         Alternative text to use in the avatar image tag. Default empty.
    2572      * @param array  $args        Arguments passed to get_avatar_data(), after processing.
    2573      */
    2574     return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
    2575 }
    2576 endif;
    2577 
    2578 if ( !function_exists( 'wp_text_diff' ) ) :
    2579 /**
    2580  * Displays a human readable HTML representation of the difference between two strings.
    2581  *
    2582  * The Diff is available for getting the changes between versions. The output is
    2583  * HTML, so the primary use is for displaying the changes. If the two strings
    2584  * are equivalent, then an empty string will be returned.
    2585  *
    2586  * The arguments supported and can be changed are listed below.
    2587  *
    2588  * 'title' : Default is an empty string. Titles the diff in a manner compatible
    2589  *      with the output.
    2590  * 'title_left' : Default is an empty string. Change the HTML to the left of the
    2591  *      title.
    2592  * 'title_right' : Default is an empty string. Change the HTML to the right of
    2593  *      the title.
    2594  *
    2595  * @since 2.6.0
    2596  *
    2597  * @see wp_parse_args() Used to change defaults to user defined settings.
    2598  * @uses Text_Diff
    2599  * @uses WP_Text_Diff_Renderer_Table
    2600  *
    2601  * @param string       $left_string  "old" (left) version of string
    2602  * @param string       $right_string "new" (right) version of string
    2603  * @param string|array $args         Optional. Change 'title', 'title_left', and 'title_right' defaults.
    2604  * @return string Empty string if strings are equivalent or HTML with differences.
    2605  */
    2606 function wp_text_diff( $left_string, $right_string, $args = null ) {
    2607     $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );
    2608     $args = wp_parse_args( $args, $defaults );
    2609 
    2610     if ( ! class_exists( 'WP_Text_Diff_Renderer_Table', false ) )
    2611         require( ABSPATH . WPINC . '/wp-diff.php' );
    2612 
    2613     $left_string  = normalize_whitespace($left_string);
    2614     $right_string = normalize_whitespace($right_string);
    2615 
    2616     $left_lines  = explode("\n", $left_string);
    2617     $right_lines = explode("\n", $right_string);
    2618     $text_diff = new Text_Diff($left_lines, $right_lines);
    2619     $renderer  = new WP_Text_Diff_Renderer_Table( $args );
    2620     $diff = $renderer->render($text_diff);
    2621 
    2622     if ( !$diff )
    2623         return '';
    2624 
    2625     $r  = "<table class='diff'>\n";
    2626 
    2627     if ( ! empty( $args[ 'show_split_view' ] ) ) {
    2628         $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
    2629     } else {
    2630         $r .= "<col class='content' />";
    2631     }
    2632 
    2633     if ( $args['title'] || $args['title_left'] || $args['title_right'] )
    2634         $r .= "<thead>";
    2635     if ( $args['title'] )
    2636         $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
    2637     if ( $args['title_left'] || $args['title_right'] ) {
    2638         $r .= "<tr class='diff-sub-title'>\n";
    2639         $r .= "\t<td></td><th>$args[title_left]</th>\n";
    2640         $r .= "\t<td></td><th>$args[title_right]</th>\n";
    2641         $r .= "</tr>\n";
    2642     }
    2643     if ( $args['title'] || $args['title_left'] || $args['title_right'] )
    2644         $r .= "</thead>\n";
    2645 
    2646     $r .= "<tbody>\n$diff\n</tbody>\n";
    2647     $r .= "</table>";
    2648 
    2649     return $r;
    2650 }
    2651 endif;
    2652 
     2671            $r .= "<col class='content' />";
     2672        }
     2673
     2674        if ( $args['title'] || $args['title_left'] || $args['title_right'] ) {
     2675            $r .= '<thead>';
     2676        }
     2677        if ( $args['title'] ) {
     2678            $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
     2679        }
     2680        if ( $args['title_left'] || $args['title_right'] ) {
     2681            $r .= "<tr class='diff-sub-title'>\n";
     2682            $r .= "\t<td></td><th>$args[title_left]</th>\n";
     2683            $r .= "\t<td></td><th>$args[title_right]</th>\n";
     2684            $r .= "</tr>\n";
     2685        }
     2686        if ( $args['title'] || $args['title_left'] || $args['title_right'] ) {
     2687            $r .= "</thead>\n";
     2688        }
     2689
     2690        $r .= "<tbody>\n$diff\n</tbody>\n";
     2691        $r .= '</table>';
     2692
     2693        return $r;
     2694    }
     2695endif;
     2696
Note: See TracChangeset for help on using the changeset viewer.