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