8 require( ABSPATH . WPINC . '/option.php' );
11 * Convert given date string into a different format.
13 * $format should be either a PHP date format string, e.g. 'U' for a Unix
14 * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT.
16 * If $translate is true then the given date and format string will
17 * be passed to date_i18n() for translation.
21 * @param string $format Format of the date to return.
22 * @param string $date Date string to convert.
23 * @param bool $translate Whether the return date should be translated. Default true.
24 * @return string|int|bool Formatted date string or Unix timestamp. False if $date is empty.
26 function mysql2date( $format, $date, $translate = true ) {
31 return strtotime( $date . ' +0000' );
33 $i = strtotime( $date );
39 return date_i18n( $format, $i );
41 return date( $format, $i );
45 * Retrieve the current time based on specified type.
47 * The 'mysql' type will return the time in the format for MySQL DATETIME field.
48 * The 'timestamp' type will return the current timestamp.
49 * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
51 * If $gmt is set to either '1' or 'true', then both types will use GMT time.
52 * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
56 * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date
57 * format string (e.g. 'Y-m-d').
58 * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false.
59 * @return int|string Integer if $type is 'timestamp', string otherwise.
61 function current_time( $type, $gmt = 0 ) {
64 return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
66 return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
68 return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
73 * Retrieve the date in localized format, based on timestamp.
75 * If the locale specifies the locale month and weekday, then the locale will
76 * take over the format for the date. If it isn't, then the date format string
77 * will be used instead.
81 * @param string $dateformatstring Format to display the date.
82 * @param bool|int $unixtimestamp Optional. Unix timestamp. Default false.
83 * @param bool $gmt Optional. Whether to use GMT timezone. Default false.
85 * @return string The date, translated if locale specifies it.
87 function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
93 $i = current_time( 'timestamp' );
96 // we should not let date() interfere with our
97 // specially computed timestamp
102 * Store original value for language with untypical grammars.
103 * See https://core.trac.wordpress.org/ticket/9396
105 $req_format = $dateformatstring;
107 $datefunc = $gmt? 'gmdate' : 'date';
109 if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
110 $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
111 $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
112 $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
113 $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
114 $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
115 $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
116 $dateformatstring = ' '.$dateformatstring;
117 $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
118 $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
119 $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
120 $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
121 $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
122 $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
124 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
126 $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
127 $timezone_formats_re = implode( '|', $timezone_formats );
128 if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
129 $timezone_string = get_option( 'timezone_string' );
130 if ( $timezone_string ) {
131 $timezone_object = timezone_open( $timezone_string );
132 $date_object = date_create( null, $timezone_object );
133 foreach( $timezone_formats as $timezone_format ) {
134 if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
135 $formatted = date_format( $date_object, $timezone_format );
136 $dateformatstring = ' '.$dateformatstring;
137 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
138 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
143 $j = @$datefunc( $dateformatstring, $i );
146 * Filter the date formatted based on the locale.
150 * @param string $j Formatted date string.
151 * @param string $req_format Format to display the date.
152 * @param int $i Unix timestamp.
153 * @param bool $gmt Whether to convert to GMT for time. Default false.
155 $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
160 * Convert integer number to format based on the locale.
164 * @param int $number The number to convert based on locale.
165 * @param int $decimals Optional. Precision of the number of decimal places. Default 0.
166 * @return string Converted number in string format.
168 function number_format_i18n( $number, $decimals = 0 ) {
170 $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
173 * Filter the number formatted based on the locale.
177 * @param string $formatted Converted number in string format.
179 return apply_filters( 'number_format_i18n', $formatted );
183 * Convert number of bytes largest unit bytes will fit into.
185 * It is easier to read 1 kB than 1024 bytes and 1 MB than 1048576 bytes. Converts
186 * number of bytes to human readable number by taking the number of that unit
187 * that the bytes will go into it. Supports TB value.
189 * Please note that integers in PHP are limited to 32 bits, unless they are on
190 * 64 bit architecture, then they have 64 bit size. If you need to place the
191 * larger size then what PHP integer type will hold, then use a string. It will
192 * be converted to a double, which should always have 64 bit length.
194 * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
198 * @param int|string $bytes Number of bytes. Note max integer size for integers.
199 * @param int $decimals Optional. Precision of number of decimal places. Default 0.
200 * @return string|false False on failure. Number string on success.
202 function size_format( $bytes, $decimals = 0 ) {
204 // ========================= Origin ====
205 'TB' => 1099511627776, // pow( 1024, 4)
206 'GB' => 1073741824, // pow( 1024, 3)
207 'MB' => 1048576, // pow( 1024, 2)
208 'kB' => 1024, // pow( 1024, 1)
209 'B' => 1, // pow( 1024, 0)
212 foreach ( $quant as $unit => $mag ) {
213 if ( doubleval( $bytes ) >= $mag ) {
214 return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
222 * Get the week start and end from the datetime or date string from MySQL.
226 * @param string $mysqlstring Date or datetime field type from MySQL.
227 * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
228 * @return array Keys are 'start' and 'end'.
230 function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
231 // MySQL string year.
232 $my = substr( $mysqlstring, 0, 4 );
234 // MySQL string month.
235 $mm = substr( $mysqlstring, 8, 2 );
238 $md = substr( $mysqlstring, 5, 2 );
240 // The timestamp for MySQL string day.
241 $day = mktime( 0, 0, 0, $md, $mm, $my );
243 // The day of the week from the timestamp.
244 $weekday = date( 'w', $day );
246 if ( !is_numeric($start_of_week) )
247 $start_of_week = get_option( 'start_of_week' );
249 if ( $weekday < $start_of_week )
252 // The most recent week start day on or before $day.
253 $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
255 // $start + 7 days - 1 second.
256 $end = $start + 7 * DAY_IN_SECONDS - 1;
257 return compact( 'start', 'end' );
261 * Unserialize value only if it was serialized.
265 * @param string $original Maybe unserialized original, if is needed.
266 * @return mixed Unserialized data can be any type.
268 function maybe_unserialize( $original ) {
269 if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
270 return @unserialize( $original );
275 * Check value to find if it was serialized.
277 * If $data is not an string, then returned value will always be false.
278 * Serialized data is always a string.
282 * @param string $data Value to check to see if was serialized.
283 * @param bool $strict Optional. Whether to be strict about the end of the string. Default true.
284 * @return bool False if not serialized and true if it was.
286 function is_serialized( $data, $strict = true ) {
287 // if it isn't a string, it isn't serialized.
288 if ( ! is_string( $data ) ) {
291 $data = trim( $data );
292 if ( 'N;' == $data ) {
295 if ( strlen( $data ) < 4 ) {
298 if ( ':' !== $data[1] ) {
302 $lastc = substr( $data, -1 );
303 if ( ';' !== $lastc && '}' !== $lastc ) {
307 $semicolon = strpos( $data, ';' );
308 $brace = strpos( $data, '}' );
309 // Either ; or } must exist.
310 if ( false === $semicolon && false === $brace )
312 // But neither must be in the first X characters.
313 if ( false !== $semicolon && $semicolon < 3 )
315 if ( false !== $brace && $brace < 4 )
322 if ( '"' !== substr( $data, -2, 1 ) ) {
325 } elseif ( false === strpos( $data, '"' ) ) {
328 // or else fall through
331 return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
335 $end = $strict ? '$' : '';
336 return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
342 * Check whether serialized data is of string type.
346 * @param string $data Serialized data.
347 * @return bool False if not a serialized string, true if it is.
349 function is_serialized_string( $data ) {
350 // if it isn't a string, it isn't a serialized string.
351 if ( ! is_string( $data ) ) {
354 $data = trim( $data );
355 if ( strlen( $data ) < 4 ) {
357 } elseif ( ':' !== $data[1] ) {
359 } elseif ( ';' !== substr( $data, -1 ) ) {
361 } elseif ( $data[0] !== 's' ) {
363 } elseif ( '"' !== substr( $data, -2, 1 ) ) {
371 * Serialize data, if needed.
375 * @param string|array|object $data Data that might be serialized.
376 * @return mixed A scalar data
378 function maybe_serialize( $data ) {
379 if ( is_array( $data ) || is_object( $data ) )
380 return serialize( $data );
382 // Double serialization is required for backward compatibility.
383 // See https://core.trac.wordpress.org/ticket/12930
384 if ( is_serialized( $data, false ) )
385 return serialize( $data );
391 * Retrieve post title from XMLRPC XML.
393 * If the title element is not part of the XML, then the default post title from
394 * the $post_default_title will be used instead.
398 * @global string $post_default_title Default XML-RPC post title.
400 * @param string $content XMLRPC XML Request content
401 * @return string Post title
403 function xmlrpc_getposttitle( $content ) {
404 global $post_default_title;
405 if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
406 $post_title = $matchtitle[1];
408 $post_title = $post_default_title;
414 * Retrieve the post category or categories from XMLRPC XML.
416 * If the category element is not found, then the default post category will be
417 * used. The return type then would be what $post_default_category. If the
418 * category is found, then it will always be an array.
422 * @global string $post_default_category Default XML-RPC post category.
424 * @param string $content XMLRPC XML Request content
425 * @return string|array List of categories or category name.
427 function xmlrpc_getpostcategory( $content ) {
428 global $post_default_category;
429 if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
430 $post_category = trim( $matchcat[1], ',' );
431 $post_category = explode( ',', $post_category );
433 $post_category = $post_default_category;
435 return $post_category;
439 * XMLRPC XML content without title and category elements.
443 * @param string $content XML-RPC XML Request content.
444 * @return string XMLRPC XML Request content without title and category elements.
446 function xmlrpc_removepostdata( $content ) {
447 $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
448 $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
449 $content = trim( $content );
454 * Use RegEx to extract URLs from arbitrary content.
458 * @param string $content Content to extract URLs from.
459 * @return array URLs found in passed string.
461 function wp_extract_urls( $content ) {
464 . "(?:([\w-]+:)?//?)"
470 . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
479 $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
481 return array_values( $post_links );
485 * Check content for video and audio links to add as enclosures.
487 * Will not add enclosures that have already been added and will
488 * remove enclosures that are no longer in the post. This is called as
489 * pingbacks and trackbacks.
495 * @param string $content Post Content.
496 * @param int $post_ID Post ID.
498 function do_enclose( $content, $post_ID ) {
501 //TODO: Tidy this ghetto code up and make the debug code optional
502 include_once( ABSPATH . WPINC . '/class-IXR.php' );
504 $post_links = array();
506 $pung = get_enclosed( $post_ID );
508 $post_links_temp = wp_extract_urls( $content );
510 foreach ( $pung as $link_test ) {
511 if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
512 $mids = $wpdb->get_col( $wpdb->prepare("SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%') );
513 foreach ( $mids as $mid )
514 delete_metadata_by_mid( 'post', $mid );
518 foreach ( (array) $post_links_temp as $link_test ) {
519 if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
520 $test = @parse_url( $link_test );
521 if ( false === $test )
523 if ( isset( $test['query'] ) )
524 $post_links[] = $link_test;
525 elseif ( isset($test['path']) && ( $test['path'] != '/' ) && ($test['path'] != '' ) )
526 $post_links[] = $link_test;
530 foreach ( (array) $post_links as $url ) {
531 if ( $url != '' && !$wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
533 if ( $headers = wp_get_http_headers( $url) ) {
534 $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
535 $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
536 $allowed_types = array( 'video', 'audio' );
538 // Check to see if we can figure out the mime type from
540 $url_parts = @parse_url( $url );
541 if ( false !== $url_parts ) {
542 $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
543 if ( !empty( $extension ) ) {
544 foreach ( wp_get_mime_types() as $exts => $mime ) {
545 if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
553 if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
554 add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
562 * Perform a HTTP HEAD or GET request.
564 * If $file_path is a writable filename, this will do a GET request and write
565 * the file to that path.
569 * @param string $url URL to fetch.
570 * @param string|bool $file_path Optional. File path to write request to. Default false.
571 * @param int $red Optional. The number of Redirects followed, Upon 5 being hit,
572 * returns false. Default 1.
573 * @return bool|string False on failure and string of headers if HEAD request.
575 function wp_get_http( $url, $file_path = false, $red = 1 ) {
576 @set_time_limit( 60 );
582 $options['redirection'] = 5;
584 if ( false == $file_path )
585 $options['method'] = 'HEAD';
587 $options['method'] = 'GET';
589 $response = wp_safe_remote_request( $url, $options );
591 if ( is_wp_error( $response ) )
594 $headers = wp_remote_retrieve_headers( $response );
595 $headers['response'] = wp_remote_retrieve_response_code( $response );
597 // WP_HTTP no longer follows redirects for HEAD requests.
598 if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) {
599 return wp_get_http( $headers['location'], $file_path, ++$red );
602 if ( false == $file_path )
605 // GET request - write it to the supplied filename
606 $out_fp = fopen($file_path, 'w');
610 fwrite( $out_fp, wp_remote_retrieve_body( $response ) );
618 * Retrieve HTTP Headers from URL.
622 * @param string $url URL to retrieve HTTP headers from.
623 * @param bool $deprecated Not Used.
624 * @return bool|string False on failure, headers on success.
626 function wp_get_http_headers( $url, $deprecated = false ) {
627 if ( !empty( $deprecated ) )
628 _deprecated_argument( __FUNCTION__, '2.7' );
630 $response = wp_safe_remote_head( $url );
632 if ( is_wp_error( $response ) )
635 return wp_remote_retrieve_headers( $response );
639 * Whether the publish date of the current post in the loop is different from the
640 * publish date of the previous post in the loop.
644 * @global string $currentday The day of the current post in the loop.
645 * @global string $previousday The day of the previous post in the loop.
647 * @return int 1 when new day, 0 if not a new day.
649 function is_new_day() {
650 global $currentday, $previousday;
651 if ( $currentday != $previousday )
658 * Build URL query based on an associative and, or indexed array.
660 * This is a convenient function for easily building url queries. It sets the
661 * separator to '&' and uses _http_build_query() function.
665 * @see _http_build_query() Used to build the query
666 * @see http://us2.php.net/manual/en/function.http-build-query.php for more on what
667 * http_build_query() does.
669 * @param array $data URL-encode key/value pairs.
670 * @return string URL-encoded string.
672 function build_query( $data ) {
673 return _http_build_query( $data, null, '&', '', false );
677 * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
682 * @see http://us1.php.net/manual/en/function.http-build-query.php
684 * @param array|object $data An array or object of data. Converted to array.
685 * @param string $prefix Optional. Numeric index. If set, start parameter numbering with it.
687 * @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'.
689 * @param string $key Optional. Used to prefix key name. Default empty.
690 * @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true.
692 * @return string The query string.
694 function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
697 foreach ( (array) $data as $k => $v ) {
700 if ( is_int($k) && $prefix != null )
703 $k = $key . '%5B' . $k . '%5D';
706 elseif ( $v === false )
709 if ( is_array($v) || is_object($v) )
710 array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
711 elseif ( $urlencode )
712 array_push($ret, $k.'='.urlencode($v));
714 array_push($ret, $k.'='.$v);
718 $sep = ini_get('arg_separator.output');
720 return implode($sep, $ret);
724 * Retrieve a modified URL query string.
726 * You can rebuild the URL and append a new query variable to the URL query by
727 * using this function. You can also retrieve the full URL with query data.
729 * Adding a single key & value or an associative array. Setting a key value to
730 * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
731 * value. Additional values provided are expected to be encoded appropriately
732 * with urlencode() or rawurlencode().
736 * @param string|array $param1 Either newkey or an associative_array.
737 * @param string $param2 Either newvalue or oldquery or URI.
738 * @param string $param3 Optional. Old query or URI.
739 * @return string New URL query string.
741 function add_query_arg() {
742 $args = func_get_args();
743 if ( is_array( $args[0] ) ) {
744 if ( count( $args ) < 2 || false === $args[1] )
745 $uri = $_SERVER['REQUEST_URI'];
749 if ( count( $args ) < 3 || false === $args[2] )
750 $uri = $_SERVER['REQUEST_URI'];
755 if ( $frag = strstr( $uri, '#' ) )
756 $uri = substr( $uri, 0, -strlen( $frag ) );
760 if ( 0 === stripos( $uri, 'http://' ) ) {
761 $protocol = 'http://';
762 $uri = substr( $uri, 7 );
763 } elseif ( 0 === stripos( $uri, 'https://' ) ) {
764 $protocol = 'https://';
765 $uri = substr( $uri, 8 );
770 if ( strpos( $uri, '?' ) !== false ) {
771 list( $base, $query ) = explode( '?', $uri, 2 );
773 } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
781 wp_parse_str( $query, $qs );
782 $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
783 if ( is_array( $args[0] ) ) {
784 foreach ( $args[0] as $k => $v ) {
788 $qs[ $args[0] ] = $args[1];
791 foreach ( $qs as $k => $v ) {
796 $ret = build_query( $qs );
797 $ret = trim( $ret, '?' );
798 $ret = preg_replace( '#=(&|$)#', '$1', $ret );
799 $ret = $protocol . $base . $ret . $frag;
800 $ret = rtrim( $ret, '?' );
805 * Removes an item or list from the query string.
809 * @param string|array $key Query key or keys to remove.
810 * @param bool|string $query Optional. When false uses the $_SERVER value. Default false.
811 * @return string New URL query string.
813 function remove_query_arg( $key, $query = false ) {
814 if ( is_array( $key ) ) { // removing multiple keys
815 foreach ( $key as $k )
816 $query = add_query_arg( $k, false, $query );
819 return add_query_arg( $key, false, $query );
823 * Walks the array while sanitizing the contents.
827 * @param array $array Array to walk while sanitizing contents.
828 * @return array Sanitized $array.
830 function add_magic_quotes( $array ) {
831 foreach ( (array) $array as $k => $v ) {
832 if ( is_array( $v ) ) {
833 $array[$k] = add_magic_quotes( $v );
835 $array[$k] = addslashes( $v );
842 * HTTP request for URI to retrieve content.
846 * @see wp_safe_remote_get()
848 * @param string $uri URI/URL of web page to retrieve.
849 * @return false|string HTTP content. False on failure.
851 function wp_remote_fopen( $uri ) {
852 $parsed_url = @parse_url( $uri );
854 if ( !$parsed_url || !is_array( $parsed_url ) )
858 $options['timeout'] = 10;
860 $response = wp_safe_remote_get( $uri, $options );
862 if ( is_wp_error( $response ) )
865 return wp_remote_retrieve_body( $response );
869 * Set up the WordPress query.
873 * @param string|array $query_vars Default WP_Query arguments.
875 function wp( $query_vars = '' ) {
876 global $wp, $wp_query, $wp_the_query;
877 $wp->main( $query_vars );
879 if ( !isset($wp_the_query) )
880 $wp_the_query = $wp_query;
884 * Retrieve the description for the HTTP status.
888 * @param int $code HTTP status code.
889 * @return string Empty string if not found, or description if found.
891 function get_status_header_desc( $code ) {
892 global $wp_header_to_desc;
894 $code = absint( $code );
896 if ( !isset( $wp_header_to_desc ) ) {
897 $wp_header_to_desc = array(
899 101 => 'Switching Protocols',
905 203 => 'Non-Authoritative Information',
907 205 => 'Reset Content',
908 206 => 'Partial Content',
909 207 => 'Multi-Status',
912 300 => 'Multiple Choices',
913 301 => 'Moved Permanently',
916 304 => 'Not Modified',
919 307 => 'Temporary Redirect',
921 400 => 'Bad Request',
922 401 => 'Unauthorized',
923 402 => 'Payment Required',
926 405 => 'Method Not Allowed',
927 406 => 'Not Acceptable',
928 407 => 'Proxy Authentication Required',
929 408 => 'Request Timeout',
932 411 => 'Length Required',
933 412 => 'Precondition Failed',
934 413 => 'Request Entity Too Large',
935 414 => 'Request-URI Too Long',
936 415 => 'Unsupported Media Type',
937 416 => 'Requested Range Not Satisfiable',
938 417 => 'Expectation Failed',
939 418 => 'I\'m a teapot',
940 422 => 'Unprocessable Entity',
942 424 => 'Failed Dependency',
943 426 => 'Upgrade Required',
944 428 => 'Precondition Required',
945 429 => 'Too Many Requests',
946 431 => 'Request Header Fields Too Large',
948 500 => 'Internal Server Error',
949 501 => 'Not Implemented',
950 502 => 'Bad Gateway',
951 503 => 'Service Unavailable',
952 504 => 'Gateway Timeout',
953 505 => 'HTTP Version Not Supported',
954 506 => 'Variant Also Negotiates',
955 507 => 'Insufficient Storage',
956 510 => 'Not Extended',
957 511 => 'Network Authentication Required',
961 if ( isset( $wp_header_to_desc[$code] ) )
962 return $wp_header_to_desc[$code];
968 * Set HTTP status header.
972 * @see get_status_header_desc()
974 * @param int $code HTTP status code.
976 function status_header( $code ) {
977 $description = get_status_header_desc( $code );
979 if ( empty( $description ) )
982 $protocol = $_SERVER['SERVER_PROTOCOL'];
983 if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
984 $protocol = 'HTTP/1.0';
985 $status_header = "$protocol $code $description";
986 if ( function_exists( 'apply_filters' ) )
989 * Filter an HTTP status header.
993 * @param string $status_header HTTP status header.
994 * @param int $code HTTP status code.
995 * @param string $description Description for the status code.
996 * @param string $protocol Server protocol.
998 $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
1000 @header( $status_header, true, $code );
1004 * Get the header information to prevent caching.
1006 * The several different headers cover the different ways cache prevention
1007 * is handled by different browsers
1011 * @return array The associative array of header names and field values.
1013 function wp_get_nocache_headers() {
1015 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
1016 'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
1017 'Pragma' => 'no-cache',
1020 if ( function_exists('apply_filters') ) {
1022 * Filter the cache-controlling headers.
1026 * @see wp_get_nocache_headers()
1028 * @param array $headers {
1029 * Header names and field values.
1031 * @type string $Expires Expires header.
1032 * @type string $Cache-Control Cache-Control header.
1033 * @type string $Pragma Pragma header.
1036 $headers = (array) apply_filters( 'nocache_headers', $headers );
1038 $headers['Last-Modified'] = false;
1043 * Set the headers to prevent caching for the different browsers.
1045 * Different browsers support different nocache headers, so several
1046 * headers must be sent so that all of them get the point that no
1047 * caching should occur.
1051 * @see wp_get_nocache_headers()
1053 function nocache_headers() {
1054 $headers = wp_get_nocache_headers();
1056 unset( $headers['Last-Modified'] );
1058 // In PHP 5.3+, make sure we are not sending a Last-Modified header.
1059 if ( function_exists( 'header_remove' ) ) {
1060 @header_remove( 'Last-Modified' );
1062 // In PHP 5.2, send an empty Last-Modified header, but only as a
1063 // last resort to override a header already sent. #WP23021
1064 foreach ( headers_list() as $header ) {
1065 if ( 0 === stripos( $header, 'Last-Modified' ) ) {
1066 $headers['Last-Modified'] = '';
1072 foreach( $headers as $name => $field_value )
1073 @header("{$name}: {$field_value}");
1077 * Set the headers for caching for 10 days with JavaScript content type.
1081 function cache_javascript_headers() {
1082 $expiresOffset = 10 * DAY_IN_SECONDS;
1084 header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
1085 header( "Vary: Accept-Encoding" ); // Handle proxies
1086 header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
1090 * Retrieve the number of database queries during the WordPress execution.
1094 * @global wpdb $wpdb WordPress database abstraction object.
1096 * @return int Number of database queries.
1098 function get_num_queries() {
1100 return $wpdb->num_queries;
1104 * Whether input is yes or no.
1106 * Must be 'y' to be true.
1110 * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
1111 * @return bool True if yes, false on anything else.
1113 function bool_from_yn( $yn ) {
1114 return ( strtolower( $yn ) == 'y' );
1118 * Load the feed template from the use of an action hook.
1120 * If the feed action does not have a hook, then the function will die with a
1121 * message telling the visitor that the feed is not valid.
1123 * It is better to only have one hook for each feed.
1127 * @uses $wp_query Used to tell if the use a comment feed.
1129 function do_feed() {
1132 $feed = get_query_var( 'feed' );
1134 // Remove the pad, if present.
1135 $feed = preg_replace( '/^_+/', '', $feed );
1137 if ( $feed == '' || $feed == 'feed' )
1138 $feed = get_default_feed();
1140 $hook = 'do_feed_' . $feed;
1141 if ( ! has_action( $hook ) )
1142 wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
1145 * Fires once the given feed is loaded.
1147 * The dynamic hook name, $hook, refers to the feed name.
1151 * @param bool $is_comment_feed Whether the feed is a comment feed.
1153 do_action( $hook, $wp_query->is_comment_feed );
1157 * Load the RDF RSS 0.91 Feed template.
1161 * @see load_template()
1163 function do_feed_rdf() {
1164 load_template( ABSPATH . WPINC . '/feed-rdf.php' );
1168 * Load the RSS 1.0 Feed Template.
1172 * @see load_template()
1174 function do_feed_rss() {
1175 load_template( ABSPATH . WPINC . '/feed-rss.php' );
1179 * Load either the RSS2 comment feed or the RSS2 posts feed.
1183 * @see load_template()
1185 * @param bool $for_comments True for the comment feed, false for normal feed.
1187 function do_feed_rss2( $for_comments ) {
1188 if ( $for_comments )
1189 load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
1191 load_template( ABSPATH . WPINC . '/feed-rss2.php' );
1195 * Load either Atom comment feed or Atom posts feed.
1199 * @see load_template()
1201 * @param bool $for_comments True for the comment feed, false for normal feed.
1203 function do_feed_atom( $for_comments ) {
1205 load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
1207 load_template( ABSPATH . WPINC . '/feed-atom.php' );
1211 * Display the robots.txt file content.
1213 * The echo content should be with usage of the permalinks or for creating the
1218 function do_robots() {
1219 header( 'Content-Type: text/plain; charset=utf-8' );
1222 * Fires when displaying the robots.txt file.
1226 do_action( 'do_robotstxt' );
1228 $output = "User-agent: *\n";
1229 $public = get_option( 'blog_public' );
1230 if ( '0' == $public ) {
1231 $output .= "Disallow: /\n";
1233 $site_url = parse_url( site_url() );
1234 $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
1235 $output .= "Disallow: $path/wp-admin/\n";
1239 * Filter the robots.txt output.
1243 * @param string $output Robots.txt output.
1244 * @param bool $public Whether the site is considered "public".
1246 echo apply_filters( 'robots_txt', $output, $public );
1250 * Test whether blog is already installed.
1252 * The cache will be checked first. If you have a cache plugin, which saves
1253 * the cache values, then this will work. If you use the default WordPress
1254 * cache, and the database goes away, then you might have problems.
1256 * Checks for the 'siteurl' option for whether WordPress is installed.
1260 * @global wpdb $wpdb WordPress database abstraction object.
1262 * @return bool Whether the blog is already installed.
1264 function is_blog_installed() {
1268 * Check cache first. If options table goes away and we have true
1271 if ( wp_cache_get( 'is_blog_installed' ) )
1274 $suppress = $wpdb->suppress_errors();
1275 if ( ! defined( 'WP_INSTALLING' ) ) {
1276 $alloptions = wp_load_alloptions();
1278 // If siteurl is not set to autoload, check it specifically
1279 if ( !isset( $alloptions['siteurl'] ) )
1280 $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
1282 $installed = $alloptions['siteurl'];
1283 $wpdb->suppress_errors( $suppress );
1285 $installed = !empty( $installed );
1286 wp_cache_set( 'is_blog_installed', $installed );
1291 // If visiting repair.php, return true and let it take over.
1292 if ( defined( 'WP_REPAIRING' ) )
1295 $suppress = $wpdb->suppress_errors();
1298 * Loop over the WP tables. If none exist, then scratch install is allowed.
1299 * If one or more exist, suggest table repair since we got here because the
1300 * options table could not be accessed.
1302 $wp_tables = $wpdb->tables();
1303 foreach ( $wp_tables as $table ) {
1304 // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
1305 if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
1307 if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
1310 if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
1313 // One or more tables exist. We are insane.
1315 wp_load_translations_early();
1317 // Die with a DB error.
1318 $wpdb->error = sprintf( __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ), 'maint/repair.php?referrer=is_blog_installed' );
1322 $wpdb->suppress_errors( $suppress );
1324 wp_cache_set( 'is_blog_installed', false );
1330 * Retrieve URL with nonce added to URL query.
1334 * @param string $actionurl URL to add nonce action.
1335 * @param int|string $action Optional. Nonce action name. Default -1.
1336 * @param string $name Optional. Nonce name. Default '_wpnonce'.
1337 * @return string Escaped URL with nonce action added.
1339 function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
1340 $actionurl = str_replace( '&', '&', $actionurl );
1341 return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
1345 * Retrieve or display nonce hidden field for forms.
1347 * The nonce field is used to validate that the contents of the form came from
1348 * the location on the current site and not somewhere else. The nonce does not
1349 * offer absolute protection, but should protect against most cases. It is very
1350 * important to use nonce field in forms.
1352 * The $action and $name are optional, but if you want to have better security,
1353 * it is strongly suggested to set those two parameters. It is easier to just
1354 * call the function without any parameters, because validation of the nonce
1355 * doesn't require any parameters, but since crackers know what the default is
1356 * it won't be difficult for them to find a way around your nonce and cause
1359 * The input name will be whatever $name value you gave. The input value will be
1360 * the nonce creation value.
1364 * @param int|string $action Optional. Action name. Default -1.
1365 * @param string $name Optional. Nonce name. Default '_wpnonce'.
1366 * @param bool $referer Optional. Whether to set the referer field for validation. Default true.
1367 * @param bool $echo Optional. Whether to display or return hidden form field. Default true.
1368 * @return string Nonce field HTML markup.
1370 function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
1371 $name = esc_attr( $name );
1372 $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
1375 $nonce_field .= wp_referer_field( false );
1380 return $nonce_field;
1384 * Retrieve or display referer hidden field for forms.
1386 * The referer link is the current Request URI from the server super global. The
1387 * input name is '_wp_http_referer', in case you wanted to check manually.
1391 * @param bool $echo Optional. Whether to echo or return the referer field. Default true.
1392 * @return string Referer field HTML markup.
1394 function wp_referer_field( $echo = true ) {
1395 $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
1398 echo $referer_field;
1399 return $referer_field;
1403 * Retrieve or display original referer hidden field for forms.
1405 * The input name is '_wp_original_http_referer' and will be either the same
1406 * value of wp_referer_field(), if that was posted already or it will be the
1407 * current page, if it doesn't exist.
1411 * @param bool $echo Optional. Whether to echo the original http referer. Default true.
1412 * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
1413 * Default 'current'.
1414 * @return string Original referer field.
1416 function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
1417 if ( ! $ref = wp_get_original_referer() ) {
1418 $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
1420 $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
1422 echo $orig_referer_field;
1423 return $orig_referer_field;
1427 * Retrieve referer from '_wp_http_referer' or HTTP referer.
1429 * If it's the same as the current request URL, will return false.
1433 * @return false|string False on failure. Referer URL on success.
1435 function wp_get_referer() {
1436 if ( ! function_exists( 'wp_validate_redirect' ) )
1439 if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
1440 $ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
1441 elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) )
1442 $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
1444 if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
1445 return wp_validate_redirect( $ref, false );
1450 * Retrieve original referer that was posted, if it exists.
1454 * @return string|false False if no original referer or original referer if set.
1456 function wp_get_original_referer() {
1457 if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
1458 return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
1463 * Recursive directory creation based on full path.
1465 * Will attempt to set permissions on folders.
1469 * @param string $target Full path to attempt to create.
1470 * @return bool Whether the path was created. True if path already exists.
1472 function wp_mkdir_p( $target ) {
1475 // Strip the protocol.
1476 if( wp_is_stream( $target ) ) {
1477 list( $wrapper, $target ) = explode( '://', $target, 2 );
1480 // From php.net/mkdir user contributed notes.
1481 $target = str_replace( '//', '/', $target );
1483 // Put the wrapper back on the target.
1484 if( $wrapper !== null ) {
1485 $target = $wrapper . '://' . $target;
1489 * Safe mode fails with a trailing slash under certain PHP versions.
1490 * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
1492 $target = rtrim($target, '/');
1493 if ( empty($target) )
1496 if ( file_exists( $target ) )
1497 return @is_dir( $target );
1499 // We need to find the permissions of the parent folder that exists and inherit that.
1500 $target_parent = dirname( $target );
1501 while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
1502 $target_parent = dirname( $target_parent );
1505 // Get the permission bits.
1506 if ( $stat = @stat( $target_parent ) ) {
1507 $dir_perms = $stat['mode'] & 0007777;
1512 if ( @mkdir( $target, $dir_perms, true ) ) {
1515 * If a umask is set that modifies $dir_perms, we'll have to re-set
1516 * the $dir_perms correctly with chmod()
1518 if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
1519 $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
1520 for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
1521 @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
1532 * Test if a give filesystem path is absolute.
1534 * For example, '/foo/bar', or 'c:\windows'.
1538 * @param string $path File path.
1539 * @return bool True if path is absolute, false is not absolute.
1541 function path_is_absolute( $path ) {
1543 * This is definitive if true but fails if $path does not exist or contains
1546 if ( realpath($path) == $path )
1549 if ( strlen($path) == 0 || $path[0] == '.' )
1552 // Windows allows absolute paths like this.
1553 if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
1556 // A path starting with / or \ is absolute; anything else is relative.
1557 return ( $path[0] == '/' || $path[0] == '\\' );
1561 * Join two filesystem paths together.
1563 * For example, 'give me $path relative to $base'. If the $path is absolute,
1564 * then it the full path is returned.
1568 * @param string $base Base path.
1569 * @param string $path Path relative to $base.
1570 * @return string The path with the base or absolute path.
1572 function path_join( $base, $path ) {
1573 if ( path_is_absolute($path) )
1576 return rtrim($base, '/') . '/' . ltrim($path, '/');
1580 * Normalize a filesystem path.
1582 * Replaces backslashes with forward slashes for Windows systems, and ensures
1583 * no duplicate slashes exist.
1587 * @param string $path Path to normalize.
1588 * @return string Normalized path.
1590 function wp_normalize_path( $path ) {
1591 $path = str_replace( '\\', '/', $path );
1592 $path = preg_replace( '|/+|','/', $path );
1597 * Determine a writable directory for temporary files.
1599 * Function's preference is the return value of sys_get_temp_dir(),
1600 * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1601 * before finally defaulting to /tmp/
1603 * In the event that this function does not find a writable location,
1604 * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
1608 * @return string Writable temporary directory.
1610 function get_temp_dir() {
1612 if ( defined('WP_TEMP_DIR') )
1613 return trailingslashit(WP_TEMP_DIR);
1616 return trailingslashit( $temp );
1618 if ( function_exists('sys_get_temp_dir') ) {
1619 $temp = sys_get_temp_dir();
1620 if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1621 return trailingslashit( $temp );
1624 $temp = ini_get('upload_tmp_dir');
1625 if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1626 return trailingslashit( $temp );
1628 $temp = WP_CONTENT_DIR . '/';
1629 if ( is_dir( $temp ) && wp_is_writable( $temp ) )
1637 * Determine if a directory is writable.
1639 * This function is used to work around certain ACL issues in PHP primarily
1640 * affecting Windows Servers.
1644 * @see win_is_writable()
1646 * @param string $path Path to check for write-ability.
1647 * @return bool Whether the path is writable.
1649 function wp_is_writable( $path ) {
1650 if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
1651 return win_is_writable( $path );
1653 return @is_writable( $path );
1657 * Workaround for Windows bug in is_writable() function
1659 * PHP has issues with Windows ACL's for determine if a
1660 * directory is writable or not, this works around them by
1661 * checking the ability to open files rather than relying
1662 * upon PHP to interprate the OS ACL.
1666 * @see http://bugs.php.net/bug.php?id=27609
1667 * @see http://bugs.php.net/bug.php?id=30931
1669 * @param string $path Windows path to check for write-ability.
1670 * @return bool Whether the path is writable.
1672 function win_is_writable( $path ) {
1674 if ( $path[strlen( $path ) - 1] == '/' ) { // if it looks like a directory, check a random file within the directory
1675 return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
1676 } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
1677 return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1679 // check tmp file for read/write capabilities
1680 $should_delete_tmp_file = !file_exists( $path );
1681 $f = @fopen( $path, 'a' );
1685 if ( $should_delete_tmp_file )
1691 * Get an array containing the current upload directory's path and url.
1693 * Checks the 'upload_path' option, which should be from the web root folder,
1694 * and if it isn't empty it will be used. If it is empty, then the path will be
1695 * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1696 * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1698 * The upload URL path is set either by the 'upload_url_path' option or by using
1699 * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1701 * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1702 * the administration settings panel), then the time will be used. The format
1703 * will be year first and then month.
1705 * If the path couldn't be created, then an error will be returned with the key
1706 * 'error' containing the error message. The error suggests that the parent
1707 * directory is not writable by the server.
1709 * On success, the returned array will have many indices:
1710 * 'path' - base directory and sub directory or full path to upload directory.
1711 * 'url' - base url and sub directory or absolute URL to upload directory.
1712 * 'subdir' - sub directory if uploads use year/month folders option is on.
1713 * 'basedir' - path without subdir.
1714 * 'baseurl' - URL path without subdir.
1715 * 'error' - set to false.
1719 * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1720 * @return array See above for description.
1722 function wp_upload_dir( $time = null ) {
1723 $siteurl = get_option( 'siteurl' );
1724 $upload_path = trim( get_option( 'upload_path' ) );
1726 if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
1727 $dir = WP_CONTENT_DIR . '/uploads';
1728 } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
1729 // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
1730 $dir = path_join( ABSPATH, $upload_path );
1732 $dir = $upload_path;
1735 if ( !$url = get_option( 'upload_url_path' ) ) {
1736 if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
1737 $url = WP_CONTENT_URL . '/uploads';
1739 $url = trailingslashit( $siteurl ) . $upload_path;
1743 * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
1744 * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
1746 if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
1747 $dir = ABSPATH . UPLOADS;
1748 $url = trailingslashit( $siteurl ) . UPLOADS;
1751 // If multisite (and if not the main site in a post-MU network)
1752 if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
1754 if ( ! get_site_option( 'ms_files_rewriting' ) ) {
1756 * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
1757 * straightforward: Append sites/%d if we're not on the main site (for post-MU
1758 * networks). (The extra directory prevents a four-digit ID from conflicting with
1759 * a year-based directory for the main site. But if a MU-era network has disabled
1760 * ms-files rewriting manually, they don't need the extra directory, as they never
1761 * had wp-content/uploads for the main site.)
1764 if ( defined( 'MULTISITE' ) )
1765 $ms_dir = '/sites/' . get_current_blog_id();
1767 $ms_dir = '/' . get_current_blog_id();
1772 } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
1774 * Handle the old-form ms-files.php rewriting if the network still has that enabled.
1775 * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
1776 * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
1778 * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
1779 * the original blog ID.
1781 * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
1782 * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
1783 * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
1784 * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
1787 if ( defined( 'BLOGUPLOADDIR' ) )
1788 $dir = untrailingslashit( BLOGUPLOADDIR );
1790 $dir = ABSPATH . UPLOADS;
1791 $url = trailingslashit( $siteurl ) . 'files';
1799 if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
1800 // Generate the yearly and monthly dirs
1802 $time = current_time( 'mysql' );
1803 $y = substr( $time, 0, 4 );
1804 $m = substr( $time, 5, 2 );
1812 * Filter the uploads directory data.
1816 * @param array $uploads Array of upload directory data with keys of 'path',
1817 * 'url', 'subdir, 'basedir', and 'error'.
1819 $uploads = apply_filters( 'upload_dir',
1823 'subdir' => $subdir,
1824 'basedir' => $basedir,
1825 'baseurl' => $baseurl,
1829 // Make sure we have an uploads directory.
1830 if ( ! wp_mkdir_p( $uploads['path'] ) ) {
1831 if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
1832 $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1834 $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1836 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1837 $uploads['error'] = $message;
1844 * Get a filename that is sanitized and unique for the given directory.
1846 * If the filename is not unique, then a number will be added to the filename
1847 * before the extension, and will continue adding numbers until the filename is
1850 * The callback is passed three parameters, the first one is the directory, the
1851 * second is the filename, and the third is the extension.
1855 * @param string $dir Directory.
1856 * @param string $filename File name.
1857 * @param callback $unique_filename_callback Callback. Default null.
1858 * @return string New filename, if given wasn't unique.
1860 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
1861 // Sanitize the file name before we begin processing.
1862 $filename = sanitize_file_name($filename);
1864 // Separate the filename into a name and extension.
1865 $info = pathinfo($filename);
1866 $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
1867 $name = basename($filename, $ext);
1869 // Edge case: if file is named '.ext', treat as an empty name.
1870 if ( $name === $ext )
1874 * Increment the file number until we have a unique file to save in $dir.
1875 * Use callback if supplied.
1877 if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
1878 $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
1882 // Change '.ext' to lower case.
1883 if ( $ext && strtolower($ext) != $ext ) {
1884 $ext2 = strtolower($ext);
1885 $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
1887 // Check for both lower and upper case extension or image sub-sizes may be overwritten.
1888 while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
1889 $new_number = $number + 1;
1890 $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
1891 $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
1892 $number = $new_number;
1897 while ( file_exists( $dir . "/$filename" ) ) {
1898 if ( '' == "$number$ext" )
1899 $filename = $filename . ++$number . $ext;
1901 $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
1909 * Create a file in the upload folder with given content.
1911 * If there is an error, then the key 'error' will exist with the error message.
1912 * If success, then the key 'file' will have the unique file path, the 'url' key
1913 * will have the link to the new file. and the 'error' key will be set to false.
1915 * This function will not move an uploaded file to the upload folder. It will
1916 * create a new file with the content in $bits parameter. If you move the upload
1917 * file, read the content of the uploaded file, and then you can give the
1918 * filename and content to this function, which will add it to the upload
1921 * The permissions will be set on the new file automatically by this function.
1925 * @param string $name Filename.
1926 * @param null|string $deprecated Never used. Set to null.
1927 * @param mixed $bits File content
1928 * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1931 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
1932 if ( !empty( $deprecated ) )
1933 _deprecated_argument( __FUNCTION__, '2.0' );
1935 if ( empty( $name ) )
1936 return array( 'error' => __( 'Empty filename' ) );
1938 $wp_filetype = wp_check_filetype( $name );
1939 if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
1940 return array( 'error' => __( 'Invalid file type' ) );
1942 $upload = wp_upload_dir( $time );
1944 if ( $upload['error'] !== false )
1948 * Filter whether to treat the upload bits as an error.
1950 * Passing a non-array to the filter will effectively short-circuit preparing
1951 * the upload bits, returning that value instead.
1955 * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
1957 $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
1958 if ( !is_array( $upload_bits_error ) ) {
1959 $upload[ 'error' ] = $upload_bits_error;
1963 $filename = wp_unique_filename( $upload['path'], $name );
1965 $new_file = $upload['path'] . "/$filename";
1966 if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
1967 if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
1968 $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
1970 $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
1972 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
1973 return array( 'error' => $message );
1976 $ifp = @ fopen( $new_file, 'wb' );
1978 return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
1980 @fwrite( $ifp, $bits );
1984 // Set correct file permissions
1985 $stat = @ stat( dirname( $new_file ) );
1986 $perms = $stat['mode'] & 0007777;
1987 $perms = $perms & 0000666;
1988 @ chmod( $new_file, $perms );
1992 $url = $upload['url'] . "/$filename";
1994 return array( 'file' => $new_file, 'url' => $url, 'error' => false );
1998 * Retrieve the file type based on the extension name.
2002 * @param string $ext The extension to search.
2003 * @return string|null The file type, example: audio, video, document, spreadsheet, etc.
2004 * Null if not found.
2006 function wp_ext2type( $ext ) {
2007 $ext = strtolower( $ext );
2010 * Filter file type based on the extension name.
2014 * @see wp_ext2type()
2016 * @param array $ext2type Multi-dimensional array with extensions for a default set
2019 $ext2type = apply_filters( 'ext2type', array(
2020 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico' ),
2021 'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
2022 'video' => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
2023 'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
2024 'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ),
2025 'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
2026 'text' => array( 'asc', 'csv', 'tsv', 'txt' ),
2027 'archive' => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ),
2028 'code' => array( 'css', 'htm', 'html', 'php', 'js' ),
2031 foreach ( $ext2type as $type => $exts )
2032 if ( in_array( $ext, $exts ) )
2039 * Retrieve the file type from the file name.
2041 * You can optionally define the mime array, if needed.
2045 * @param string $filename File name or path.
2046 * @param array $mimes Optional. Key is the file extension with value as the mime type.
2047 * @return array Values with extension first and mime type.
2049 function wp_check_filetype( $filename, $mimes = null ) {
2050 if ( empty($mimes) )
2051 $mimes = get_allowed_mime_types();
2055 foreach ( $mimes as $ext_preg => $mime_match ) {
2056 $ext_preg = '!\.(' . $ext_preg . ')$!i';
2057 if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
2058 $type = $mime_match;
2059 $ext = $ext_matches[1];
2064 return compact( 'ext', 'type' );
2068 * Attempt to determine the real file type of a file.
2070 * If unable to, the file name extension will be used to determine type.
2072 * If it's determined that the extension does not match the file's real type,
2073 * then the "proper_filename" value will be set with a proper filename and extension.
2075 * Currently this function only supports validating images known to getimagesize().
2079 * @param string $file Full path to the file.
2080 * @param string $filename The name of the file (may differ from $file due to $file being
2081 * in a tmp directory).
2082 * @param array $mimes Optional. Key is the file extension with value as the mime type.
2083 * @return array Values for the extension, MIME, and either a corrected filename or false
2084 * if original $filename is valid.
2086 function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
2088 $proper_filename = false;
2090 // Do basic extension validation and MIME mapping
2091 $wp_filetype = wp_check_filetype( $filename, $mimes );
2092 $ext = $wp_filetype['ext'];
2093 $type = $wp_filetype['type'];
2095 // We can't do any further validation without a file to work with
2096 if ( ! file_exists( $file ) ) {
2097 return compact( 'ext', 'type', 'proper_filename' );
2100 // We're able to validate images using GD
2101 if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
2103 // Attempt to figure out what type of image it actually is
2104 $imgstats = @getimagesize( $file );
2106 // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
2107 if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
2109 * Filter the list mapping image mime types to their respective extensions.
2113 * @param array $mime_to_ext Array of image mime types and their matching extensions.
2115 $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
2116 'image/jpeg' => 'jpg',
2117 'image/png' => 'png',
2118 'image/gif' => 'gif',
2119 'image/bmp' => 'bmp',
2120 'image/tiff' => 'tif',
2123 // Replace whatever is after the last period in the filename with the correct extension
2124 if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
2125 $filename_parts = explode( '.', $filename );
2126 array_pop( $filename_parts );
2127 $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
2128 $new_filename = implode( '.', $filename_parts );
2130 if ( $new_filename != $filename ) {
2131 $proper_filename = $new_filename; // Mark that it changed
2133 // Redefine the extension / MIME
2134 $wp_filetype = wp_check_filetype( $new_filename, $mimes );
2135 $ext = $wp_filetype['ext'];
2136 $type = $wp_filetype['type'];
2142 * Filter the "real" file type of the given file.
2146 * @param array $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
2147 * 'proper_filename' keys.
2148 * @param string $file Full path to the file.
2149 * @param string $filename The name of the file (may differ from $file due to
2150 * $file being in a tmp directory).
2151 * @param array $mimes Key is the file extension with value as the mime type.
2153 return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
2157 * Retrieve list of mime types and file extensions.
2160 * @since 4.2.0 Support was added for GIMP (xcf) files.
2162 * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2164 function wp_get_mime_types() {
2166 * Filter the list of mime types and file extensions.
2168 * This filter should be used to add, not remove, mime types. To remove
2169 * mime types, use the 'upload_mimes' filter.
2173 * @param array $wp_get_mime_types Mime types keyed by the file extension regex
2174 * corresponding to those types.
2176 return apply_filters( 'mime_types', array(
2178 'jpg|jpeg|jpe' => 'image/jpeg',
2179 'gif' => 'image/gif',
2180 'png' => 'image/png',
2181 'bmp' => 'image/bmp',
2182 'tiff|tif' => 'image/tiff',
2183 'ico' => 'image/x-icon',
2185 'asf|asx' => 'video/x-ms-asf',
2186 'wmv' => 'video/x-ms-wmv',
2187 'wmx' => 'video/x-ms-wmx',
2188 'wm' => 'video/x-ms-wm',
2189 'avi' => 'video/avi',
2190 'divx' => 'video/divx',
2191 'flv' => 'video/x-flv',
2192 'mov|qt' => 'video/quicktime',
2193 'mpeg|mpg|mpe' => 'video/mpeg',
2194 'mp4|m4v' => 'video/mp4',
2195 'ogv' => 'video/ogg',
2196 'webm' => 'video/webm',
2197 'mkv' => 'video/x-matroska',
2198 '3gp|3gpp' => 'video/3gpp', // Can also be audio
2199 '3g2|3gp2' => 'video/3gpp2', // Can also be audio
2201 'txt|asc|c|cc|h|srt' => 'text/plain',
2202 'csv' => 'text/csv',
2203 'tsv' => 'text/tab-separated-values',
2204 'ics' => 'text/calendar',
2205 'rtx' => 'text/richtext',
2206 'css' => 'text/css',
2207 'htm|html' => 'text/html',
2208 'vtt' => 'text/vtt',
2209 'dfxp' => 'application/ttaf+xml',
2211 'mp3|m4a|m4b' => 'audio/mpeg',
2212 'ra|ram' => 'audio/x-realaudio',
2213 'wav' => 'audio/wav',
2214 'ogg|oga' => 'audio/ogg',
2215 'mid|midi' => 'audio/midi',
2216 'wma' => 'audio/x-ms-wma',
2217 'wax' => 'audio/x-ms-wax',
2218 'mka' => 'audio/x-matroska',
2219 // Misc application formats.
2220 'rtf' => 'application/rtf',
2221 'js' => 'application/javascript',
2222 'pdf' => 'application/pdf',
2223 'swf' => 'application/x-shockwave-flash',
2224 'class' => 'application/java',
2225 'tar' => 'application/x-tar',
2226 'zip' => 'application/zip',
2227 'gz|gzip' => 'application/x-gzip',
2228 'rar' => 'application/rar',
2229 '7z' => 'application/x-7z-compressed',
2230 'exe' => 'application/x-msdownload',
2231 'psd' => 'application/octet-stream',
2232 'xcf' => 'application/octet-stream',
2233 // MS Office formats.
2234 'doc' => 'application/msword',
2235 'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
2236 'wri' => 'application/vnd.ms-write',
2237 'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2238 'mdb' => 'application/vnd.ms-access',
2239 'mpp' => 'application/vnd.ms-project',
2240 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2241 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2242 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2243 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2244 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2245 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2246 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2247 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2248 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2249 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2250 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2251 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2252 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2253 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2254 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2255 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2256 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2257 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2258 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2259 'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2260 'oxps' => 'application/oxps',
2261 'xps' => 'application/vnd.ms-xpsdocument',
2262 // OpenOffice formats.
2263 'odt' => 'application/vnd.oasis.opendocument.text',
2264 'odp' => 'application/vnd.oasis.opendocument.presentation',
2265 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2266 'odg' => 'application/vnd.oasis.opendocument.graphics',
2267 'odc' => 'application/vnd.oasis.opendocument.chart',
2268 'odb' => 'application/vnd.oasis.opendocument.database',
2269 'odf' => 'application/vnd.oasis.opendocument.formula',
2270 // WordPerfect formats.
2271 'wp|wpd' => 'application/wordperfect',
2273 'key' => 'application/vnd.apple.keynote',
2274 'numbers' => 'application/vnd.apple.numbers',
2275 'pages' => 'application/vnd.apple.pages',
2279 * Retrieve list of allowed mime types and file extensions.
2283 * @param int|WP_User $user Optional. User to check. Defaults to current user.
2284 * @return array Array of mime types keyed by the file extension regex corresponding
2287 function get_allowed_mime_types( $user = null ) {
2288 $t = wp_get_mime_types();
2290 unset( $t['swf'], $t['exe'] );
2291 if ( function_exists( 'current_user_can' ) )
2292 $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2294 if ( empty( $unfiltered ) )
2295 unset( $t['htm|html'] );
2298 * Filter list of allowed mime types and file extensions.
2302 * @param array $t Mime types keyed by the file extension regex corresponding to
2303 * those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2304 * removed depending on '$user' capabilities.
2305 * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2307 return apply_filters( 'upload_mimes', $t, $user );
2311 * Display "Are You Sure" message to confirm the action being taken.
2313 * If the action has the nonce explain message, then it will be displayed
2314 * along with the "Are you sure?" message.
2318 * @param string $action The nonce action.
2320 function wp_nonce_ays( $action ) {
2321 if ( 'log-out' == $action ) {
2322 $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
2323 $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2324 $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url( $redirect_to ) );
2326 $html = __( 'Are you sure you want to do this?' );
2327 if ( wp_get_referer() )
2328 $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
2331 wp_die( $html, __( 'WordPress Failure Notice' ), 403 );
2335 * Kill WordPress execution and display HTML message with error message.
2337 * This function complements the `die()` PHP function. The difference is that
2338 * HTML will be displayed to the user. It is recommended to use this function
2339 * only when the execution should not continue any further. It is not recommended
2340 * to call this function very often, and try to handle as many errors as possible
2341 * silently or more gracefully.
2343 * As a shorthand, the desired HTTP response code may be passed as an integer to
2344 * the `$title` parameter (the default title would apply) or the `$args` parameter.
2347 * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
2348 * an integer to be used as the response code.
2350 * @param string|WP_Error $message Optional. Error message. If this is a {@see WP_Error} object,
2351 * the error's messages are used. Default empty.
2352 * @param string|int $title Optional. Error title. If `$message` is a `WP_Error` object,
2353 * error data with the key 'title' may be used to specify the title.
2354 * If `$title` is an integer, then it is treated as the response
2355 * code. Default empty.
2356 * @param string|array|int $args {
2357 * Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
2358 * as the response code. Default empty array.
2360 * @type int $response The HTTP response code. Default 500.
2361 * @type bool $back_link Whether to include a link to go back. Default false.
2362 * @type string $text_direction The text direction. This is only useful internally, when WordPress
2363 * is still loading and the site's locale is not set up yet. Accepts 'rtl'.
2364 * Default is the value of {@see is_rtl()}.
2367 function wp_die( $message = '', $title = '', $args = array() ) {
2369 if ( is_int( $args ) ) {
2370 $args = array( 'response' => $args );
2371 } elseif ( is_int( $title ) ) {
2372 $args = array( 'response' => $title );
2376 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2378 * Filter callback for killing WordPress execution for AJAX requests.
2382 * @param callback $function Callback function name.
2384 $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2385 } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2387 * Filter callback for killing WordPress execution for XML-RPC requests.
2391 * @param callback $function Callback function name.
2393 $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2396 * Filter callback for killing WordPress execution for all non-AJAX, non-XML-RPC requests.
2400 * @param callback $function Callback function name.
2402 $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2405 call_user_func( $function, $message, $title, $args );
2409 * Kill WordPress execution and display HTML message with error message.
2411 * This is the default handler for wp_die if you want a custom one for your
2412 * site then you can overload using the wp_die_handler filter in wp_die
2417 * @param string $message Error message.
2418 * @param string $title Optional. Error title. Default empty.
2419 * @param string|array $args Optional. Arguments to control behavior. Default empty array.
2421 function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2422 $defaults = array( 'response' => 500 );
2423 $r = wp_parse_args($args, $defaults);
2425 $have_gettext = function_exists('__');
2427 if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2428 if ( empty( $title ) ) {
2429 $error_data = $message->get_error_data();
2430 if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2431 $title = $error_data['title'];
2433 $errors = $message->get_error_messages();
2434 switch ( count( $errors ) ) {
2439 $message = "<p>{$errors[0]}</p>";
2442 $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2445 } elseif ( is_string( $message ) ) {
2446 $message = "<p>$message</p>";
2449 if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2450 $back_text = $have_gettext? __('« Back') : '« Back';
2451 $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2454 if ( ! did_action( 'admin_head' ) ) :
2455 if ( !headers_sent() ) {
2456 status_header( $r['response'] );
2458 header( 'Content-Type: text/html; charset=utf-8' );
2461 if ( empty($title) )
2462 $title = $have_gettext ? __('WordPress › Error') : 'WordPress › Error';
2464 $text_direction = 'ltr';
2465 if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2466 $text_direction = 'rtl';
2467 elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2468 $text_direction = 'rtl';
2471 <!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono
2473 <html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) language_attributes(); else echo "dir='$text_direction'"; ?>>
2475 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2476 <title><?php echo $title ?></title>
2477 <style type="text/css">
2479 background: #f1f1f1;
2484 font-family: "Open Sans", sans-serif;
2488 -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2489 box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2492 border-bottom: 1px solid #dadada;
2495 font: 24px "Open Sans", sans-serif;
2498 padding-bottom: 7px;
2506 margin: 25px 0 20px;
2509 font-family: Consolas, Monaco, monospace;
2512 margin-bottom: 10px;
2517 text-decoration: none;
2523 background: #f7f7f7;
2524 border: 1px solid #cccccc;
2526 display: inline-block;
2527 text-decoration: none;
2532 padding: 0 10px 1px;
2534 -webkit-border-radius: 3px;
2535 -webkit-appearance: none;
2537 white-space: nowrap;
2538 -webkit-box-sizing: border-box;
2539 -moz-box-sizing: border-box;
2540 box-sizing: border-box;
2542 -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2543 box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0,0,0,.08);
2544 vertical-align: top;
2547 .button.button-large {
2555 background: #fafafa;
2561 -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2562 box-shadow: 1px 1px 1px rgba(0,0,0,.2);
2569 -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2570 box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2573 <?php if ( 'rtl' == $text_direction ) : ?>
2574 body { font-family: Tahoma, Arial; }
2578 <body id="error-page">
2579 <?php endif; // ! did_action( 'admin_head' ) ?>
2580 <?php echo $message; ?>
2588 * Kill WordPress execution and display XML message with error message.
2590 * This is the handler for wp_die when processing XMLRPC requests.
2595 * @param string $message Error message.
2596 * @param string $title Optional. Error title. Default empty.
2597 * @param string|array $args Optional. Arguments to control behavior. Default empty array.
2599 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2600 global $wp_xmlrpc_server;
2601 $defaults = array( 'response' => 500 );
2603 $r = wp_parse_args($args, $defaults);
2605 if ( $wp_xmlrpc_server ) {
2606 $error = new IXR_Error( $r['response'] , $message);
2607 $wp_xmlrpc_server->output( $error->getXml() );
2613 * Kill WordPress ajax execution.
2615 * This is the handler for wp_die when processing Ajax requests.
2620 * @param string $message Optional. Response to print. Default empty.
2622 function _ajax_wp_die_handler( $message = '' ) {
2623 if ( is_scalar( $message ) )
2624 die( (string) $message );
2629 * Kill WordPress execution.
2631 * This is the handler for wp_die when processing APP requests.
2636 * @param string $message Optional. Response to print. Default empty.
2638 function _scalar_wp_die_handler( $message = '' ) {
2639 if ( is_scalar( $message ) )
2640 die( (string) $message );
2645 * Encode a variable into JSON, with some sanity checks.
2649 * @param mixed $data Variable (usually an array or object) to encode as JSON.
2650 * @param int $options Optional. Options to be passed to json_encode(). Default 0.
2651 * @param int $depth Optional. Maximum depth to walk through $data. Must be
2652 * greater than 0. Default 512.
2653 * @return bool|string The JSON encoded string, or false if it cannot be encoded.
2655 function wp_json_encode( $data, $options = 0, $depth = 512 ) {
2657 * json_encode() has had extra params added over the years.
2658 * $options was added in 5.3, and $depth in 5.5.
2659 * We need to make sure we call it with the correct arguments.
2661 if ( version_compare( PHP_VERSION, '5.5', '>=' ) ) {
2662 $args = array( $data, $options, $depth );
2663 } elseif ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
2664 $args = array( $data, $options );
2666 $args = array( $data );
2669 $json = call_user_func_array( 'json_encode', $args );
2671 // If json_encode() was successful, no need to do more sanity checking.
2672 // ... unless we're in an old version of PHP, and json_encode() returned
2673 // a string containing 'null'. Then we need to do more sanity checking.
2674 if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) ) {
2679 $args[0] = _wp_json_sanity_check( $data, $depth );
2680 } catch ( Exception $e ) {
2684 return call_user_func_array( 'json_encode', $args );
2688 * Perform sanity checks on data that shall be encoded to JSON.
2694 * @see wp_json_encode()
2696 * @param mixed $data Variable (usually an array or object) to encode as JSON.
2697 * @param int $depth Maximum depth to walk through $data. Must be greater than 0.
2698 * @return mixed The sanitized data that shall be encoded to JSON.
2700 function _wp_json_sanity_check( $data, $depth ) {
2702 throw new Exception( 'Reached depth limit' );
2705 if ( is_array( $data ) ) {
2707 foreach ( $data as $id => $el ) {
2708 // Don't forget to sanitize the ID!
2709 if ( is_string( $id ) ) {
2710 $clean_id = _wp_json_convert_string( $id );
2715 // Check the element type, so that we're only recursing if we really have to.
2716 if ( is_array( $el ) || is_object( $el ) ) {
2717 $output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
2718 } elseif ( is_string( $el ) ) {
2719 $output[ $clean_id ] = _wp_json_convert_string( $el );
2721 $output[ $clean_id ] = $el;
2724 } elseif ( is_object( $data ) ) {
2725 $output = new stdClass;
2726 foreach ( $data as $id => $el ) {
2727 if ( is_string( $id ) ) {
2728 $clean_id = _wp_json_convert_string( $id );
2733 if ( is_array( $el ) || is_object( $el ) ) {
2734 $output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
2735 } elseif ( is_string( $el ) ) {
2736 $output->$clean_id = _wp_json_convert_string( $el );
2738 $output->$clean_id = $el;
2741 } elseif ( is_string( $data ) ) {
2742 return _wp_json_convert_string( $data );
2751 * Convert a string to UTF-8, so that it can be safely encoded to JSON.
2757 * @see _wp_json_sanity_check()
2759 * @param string $string The string which is to be converted.
2760 * @return string The checked string.
2762 function _wp_json_convert_string( $string ) {
2763 static $use_mb = null;
2764 if ( is_null( $use_mb ) ) {
2765 $use_mb = function_exists( 'mb_convert_encoding' );
2769 $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
2771 return mb_convert_encoding( $string, 'UTF-8', $encoding );
2773 return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
2776 return wp_check_invalid_utf8( $string, true );
2781 * Send a JSON response back to an Ajax request.
2785 * @param mixed $response Variable (usually an array or object) to encode as JSON,
2786 * then print and die.
2788 function wp_send_json( $response ) {
2789 @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
2790 echo wp_json_encode( $response );
2791 if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
2798 * Send a JSON response back to an Ajax request, indicating success.
2802 * @param mixed $data Data to encode as JSON, then print and die.
2804 function wp_send_json_success( $data = null ) {
2805 $response = array( 'success' => true );
2807 if ( isset( $data ) )
2808 $response['data'] = $data;
2810 wp_send_json( $response );
2814 * Send a JSON response back to an Ajax request, indicating failure.
2816 * If the `$data` parameter is a {@see WP_Error} object, the errors
2817 * within the object are processed and output as an array of error
2818 * codes and corresponding messages. All other types are output
2819 * without further processing.
2822 * @since 4.1.0 The `$data` parameter is now processed if a {@see WP_Error}
2823 * object is passed in.
2825 * @param mixed $data Data to encode as JSON, then print and die.
2827 function wp_send_json_error( $data = null ) {
2828 $response = array( 'success' => false );
2830 if ( isset( $data ) ) {
2831 if ( is_wp_error( $data ) ) {
2833 foreach ( $data->errors as $code => $messages ) {
2834 foreach ( $messages as $message ) {
2835 $result[] = array( 'code' => $code, 'message' => $message );
2839 $response['data'] = $result;
2841 $response['data'] = $data;
2845 wp_send_json( $response );
2849 * Retrieve the WordPress home page URL.
2851 * If the constant named 'WP_HOME' exists, then it will be used and returned
2852 * by the function. This can be used to counter the redirection on your local
2853 * development environment.
2860 * @param string $url URL for the home location.
2861 * @return string Homepage location.
2863 function _config_wp_home( $url = '' ) {
2864 if ( defined( 'WP_HOME' ) )
2865 return untrailingslashit( WP_HOME );
2870 * Retrieve the WordPress site URL.
2872 * If the constant named 'WP_SITEURL' is defined, then the value in that
2873 * constant will always be returned. This can be used for debugging a site
2874 * on your localhost while not having to change the database to your URL.
2881 * @param string $url URL to set the WordPress site location.
2882 * @return string The WordPress Site URL.
2884 function _config_wp_siteurl( $url = '' ) {
2885 if ( defined( 'WP_SITEURL' ) )
2886 return untrailingslashit( WP_SITEURL );
2891 * Set the localized direction for MCE plugin.
2893 * Will only set the direction to 'rtl', if the WordPress locale has
2894 * the text direction set to 'rtl'.
2896 * Fills in the 'directionality' setting, enables the 'directionality'
2897 * plugin, and adds the 'ltr' button to 'toolbar1', formerly
2898 * 'theme_advanced_buttons1' array keys. These keys are then returned
2899 * in the $input (TinyMCE settings) array.
2904 * @param array $input MCE settings array.
2905 * @return array Direction set for 'rtl', if needed by locale.
2907 function _mce_set_direction( $input ) {
2909 $input['directionality'] = 'rtl';
2911 if ( ! empty( $input['plugins'] ) && strpos( $input['plugins'], 'directionality' ) === false ) {
2912 $input['plugins'] .= ',directionality';
2915 if ( ! empty( $input['toolbar1'] ) && ! preg_match( '/\bltr\b/', $input['toolbar1'] ) ) {
2916 $input['toolbar1'] .= ',ltr';
2925 * Convert smiley code to the icon graphic file equivalent.
2927 * You can turn off smilies, by going to the write setting screen and unchecking
2928 * the box, or by setting 'use_smilies' option to false or removing the option.
2930 * Plugins may override the default smiley list by setting the $wpsmiliestrans
2931 * to an array, with the key the code the blogger types in and the value the
2934 * The $wp_smiliessearch global is for the regular expression and is set each
2935 * time the function is called.
2937 * The full list of smilies can be found in the function and won't be listed in
2938 * the description. Probably should create a Codex page for it, so that it is
2941 * @global array $wpsmiliestrans
2942 * @global array $wp_smiliessearch
2946 function smilies_init() {
2947 global $wpsmiliestrans, $wp_smiliessearch;
2949 // don't bother setting up smilies if they are disabled
2950 if ( !get_option( 'use_smilies' ) )
2953 if ( !isset( $wpsmiliestrans ) ) {
2954 $wpsmiliestrans = array(
2955 ':mrgreen:' => 'mrgreen.png',
2956 ':neutral:' => "\xf0\x9f\x98\x90",
2957 ':twisted:' => "\xf0\x9f\x98\x88",
2958 ':arrow:' => "\xe2\x9e\xa1",
2959 ':shock:' => "\xf0\x9f\x98\xaf",
2960 ':smile:' => 'simple-smile.png',
2961 ':???:' => "\xf0\x9f\x98\x95",
2962 ':cool:' => "\xf0\x9f\x98\x8e",
2963 ':evil:' => "\xf0\x9f\x91\xbf",
2964 ':grin:' => "\xf0\x9f\x98\x80",
2965 ':idea:' => "\xf0\x9f\x92\xa1",
2966 ':oops:' => "\xf0\x9f\x98\xb3",
2967 ':razz:' => "\xf0\x9f\x98\x9b",
2968 ':roll:' => 'rolleyes.png',
2969 ':wink:' => "\xf0\x9f\x98\x89",
2970 ':cry:' => "\xf0\x9f\x98\xa5",
2971 ':eek:' => "\xf0\x9f\x98\xae",
2972 ':lol:' => "\xf0\x9f\x98\x86",
2973 ':mad:' => "\xf0\x9f\x98\xa1",
2974 ':sad:' => 'frownie.png',
2975 '8-)' => "\xf0\x9f\x98\x8e",
2976 '8-O' => "\xf0\x9f\x98\xaf",
2977 ':-(' => 'frownie.png',
2978 ':-)' => 'simple-smile.png',
2979 ':-?' => "\xf0\x9f\x98\x95",
2980 ':-D' => "\xf0\x9f\x98\x80",
2981 ':-P' => "\xf0\x9f\x98\x9b",
2982 ':-o' => "\xf0\x9f\x98\xae",
2983 ':-x' => "\xf0\x9f\x98\xa1",
2984 ':-|' => "\xf0\x9f\x98\x90",
2985 ';-)' => "\xf0\x9f\x98\x89",
2986 // This one transformation breaks regular text with frequency.
2987 // '8)' => "\xf0\x9f\x98\x8e",
2988 '8O' => "\xf0\x9f\x98\xaf",
2989 ':(' => 'frownie.png',
2990 ':)' => 'simple-smile.png',
2991 ':?' => "\xf0\x9f\x98\x95",
2992 ':D' => "\xf0\x9f\x98\x80",
2993 ':P' => "\xf0\x9f\x98\x9b",
2994 ':o' => "\xf0\x9f\x98\xae",
2995 ':x' => "\xf0\x9f\x98\xa1",
2996 ':|' => "\xf0\x9f\x98\x90",
2997 ';)' => "\xf0\x9f\x98\x89",
2998 ':!:' => "\xe2\x9d\x97",
2999 ':?:' => "\xe2\x9d\x93",
3003 if (count($wpsmiliestrans) == 0) {
3008 * NOTE: we sort the smilies in reverse key order. This is to make sure
3009 * we match the longest possible smilie (:???: vs :?) as the regular
3010 * expression used below is first-match
3012 krsort($wpsmiliestrans);
3014 $spaces = wp_spaces_regexp();
3016 // Begin first "subpattern"
3017 $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
3020 foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
3021 $firstchar = substr($smiley, 0, 1);
3022 $rest = substr($smiley, 1);
3025 if ($firstchar != $subchar) {
3026 if ($subchar != '') {
3027 $wp_smiliessearch .= ')(?=' . $spaces . '|$)'; // End previous "subpattern"
3028 $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
3030 $subchar = $firstchar;
3031 $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
3033 $wp_smiliessearch .= '|';
3035 $wp_smiliessearch .= preg_quote($rest, '/');
3038 $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
3043 * Merge user defined arguments into defaults array.
3045 * This function is used throughout WordPress to allow for both string or array
3046 * to be merged into another array.
3050 * @param string|array $args Value to merge with $defaults
3051 * @param array $defaults Optional. Array that serves as the defaults. Default empty.
3052 * @return array Merged user defined values with defaults.
3054 function wp_parse_args( $args, $defaults = '' ) {
3055 if ( is_object( $args ) )
3056 $r = get_object_vars( $args );
3057 elseif ( is_array( $args ) )
3060 wp_parse_str( $args, $r );
3062 if ( is_array( $defaults ) )
3063 return array_merge( $defaults, $r );
3068 * Clean up an array, comma- or space-separated list of IDs.
3072 * @param array|string $list List of ids.
3073 * @return array Sanitized array of IDs.
3075 function wp_parse_id_list( $list ) {
3076 if ( !is_array($list) )
3077 $list = preg_split('/[\s,]+/', $list);
3079 return array_unique(array_map('absint', $list));
3083 * Extract a slice of an array, given a list of keys.
3087 * @param array $array The original array.
3088 * @param array $keys The list of keys.
3089 * @return array The array slice.
3091 function wp_array_slice_assoc( $array, $keys ) {
3093 foreach ( $keys as $key )
3094 if ( isset( $array[ $key ] ) )
3095 $slice[ $key ] = $array[ $key ];
3101 * Filters a list of objects, based on a set of key => value arguments.
3105 * @param array $list An array of objects to filter
3106 * @param array $args Optional. An array of key => value arguments to match
3107 * against each object. Default empty array.
3108 * @param string $operator Optional. The logical operation to perform. 'or' means
3109 * only one element from the array needs to match; 'and'
3110 * means all elements must match. Default 'and'.
3111 * @param bool|string $field A field from the object to place instead of the entire object.
3113 * @return array A list of objects or object fields.
3115 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
3116 if ( ! is_array( $list ) )
3119 $list = wp_list_filter( $list, $args, $operator );
3122 $list = wp_list_pluck( $list, $field );
3128 * Filters a list of objects, based on a set of key => value arguments.
3132 * @param array $list An array of objects to filter.
3133 * @param array $args Optional. An array of key => value arguments to match
3134 * against each object. Default empty array.
3135 * @param string $operator Optional. The logical operation to perform. 'AND' means
3136 * all elements from the array must match. 'OR' means only
3137 * one element needs to match. 'NOT' means no elements may
3138 * match. Default 'AND'.
3139 * @return array Array of found values.
3141 function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
3142 if ( ! is_array( $list ) )
3145 if ( empty( $args ) )
3148 $operator = strtoupper( $operator );
3149 $count = count( $args );
3150 $filtered = array();
3152 foreach ( $list as $key => $obj ) {
3153 $to_match = (array) $obj;
3156 foreach ( $args as $m_key => $m_value ) {
3157 if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
3161 if ( ( 'AND' == $operator && $matched == $count )
3162 || ( 'OR' == $operator && $matched > 0 )
3163 || ( 'NOT' == $operator && 0 == $matched ) ) {
3164 $filtered[$key] = $obj;
3172 * Pluck a certain field out of each object in a list.
3174 * This has the same functionality and prototype of
3175 * array_column() (PHP 5.5) but also supports objects.
3178 * @since 4.0.0 $index_key parameter added.
3180 * @param array $list List of objects or arrays
3181 * @param int|string $field Field from the object to place instead of the entire object
3182 * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
3184 * @return array Array of found values. If `$index_key` is set, an array of found values with keys
3185 * corresponding to `$index_key`. If `$index_key` is null, array keys from the original
3186 * `$list` will be preserved in the results.
3188 function wp_list_pluck( $list, $field, $index_key = null ) {
3189 if ( ! $index_key ) {
3191 * This is simple. Could at some point wrap array_column()
3192 * if we knew we had an array of arrays.
3194 foreach ( $list as $key => $value ) {
3195 if ( is_object( $value ) ) {
3196 $list[ $key ] = $value->$field;
3198 $list[ $key ] = $value[ $field ];
3205 * When index_key is not set for a particular item, push the value
3206 * to the end of the stack. This is how array_column() behaves.
3209 foreach ( $list as $value ) {
3210 if ( is_object( $value ) ) {
3211 if ( isset( $value->$index_key ) ) {
3212 $newlist[ $value->$index_key ] = $value->$field;
3214 $newlist[] = $value->$field;
3217 if ( isset( $value[ $index_key ] ) ) {
3218 $newlist[ $value[ $index_key ] ] = $value[ $field ];
3220 $newlist[] = $value[ $field ];
3229 * Determines if Widgets library should be loaded.
3231 * Checks to make sure that the widgets library hasn't already been loaded.
3232 * If it hasn't, then it will load the widgets library and run an action hook.
3236 function wp_maybe_load_widgets() {
3238 * Filter whether to load the Widgets library.
3240 * Passing a falsey value to the filter will effectively short-circuit
3241 * the Widgets library from loading.
3245 * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
3248 if ( ! apply_filters( 'load_default_widgets', true ) ) {
3252 require_once( ABSPATH . WPINC . '/default-widgets.php' );
3254 add_action( '_admin_menu', 'wp_widgets_add_menu' );
3258 * Append the Widgets menu to the themes main menu.
3262 function wp_widgets_add_menu() {
3265 if ( ! current_theme_supports( 'widgets' ) )
3268 $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
3269 ksort( $submenu['themes.php'], SORT_NUMERIC );
3273 * Flush all output buffers for PHP 5.2.
3275 * Make sure all output buffers are flushed before our singletons are destroyed.
3279 function wp_ob_end_flush_all() {
3280 $levels = ob_get_level();
3281 for ($i=0; $i<$levels; $i++)
3286 * Load custom DB error or display WordPress DB error.
3288 * If a file exists in the wp-content directory named db-error.php, then it will
3289 * be loaded instead of displaying the WordPress DB error. If it is not found,
3290 * then the WordPress DB error will be displayed instead.
3292 * The WordPress DB error sets the HTTP status header to 500 to try to prevent
3293 * search engines from caching the message. Custom DB messages should do the
3296 * This function was backported to WordPress 2.3.2, but originally was added
3297 * in WordPress 2.5.0.
3301 * @global wpdb $wpdb WordPress database abstraction object.
3303 function dead_db() {
3306 wp_load_translations_early();
3308 // Load custom DB error template, if present.
3309 if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
3310 require_once( WP_CONTENT_DIR . '/db-error.php' );
3314 // If installing or in the admin, provide the verbose message.
3315 if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
3316 wp_die($wpdb->error);
3318 // Otherwise, be terse.
3319 status_header( 500 );
3321 header( 'Content-Type: text/html; charset=utf-8' );
3324 <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
3326 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3327 <title><?php _e( 'Database Error' ); ?></title>
3331 <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
3339 * Convert a value to non-negative integer.
3343 * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
3344 * @return int A non-negative integer.
3346 function absint( $maybeint ) {
3347 return abs( intval( $maybeint ) );
3351 * Mark a function as deprecated and inform when it has been used.
3353 * There is a hook deprecated_function_run that will be called that can be used
3354 * to get the backtrace up to what file and function called the deprecated
3357 * The current behavior is to trigger a user error if WP_DEBUG is true.
3359 * This function is to be used in every function that is deprecated.
3364 * @param string $function The function that was called.
3365 * @param string $version The version of WordPress that deprecated the function.
3366 * @param string $replacement Optional. The function that should have been called. Default null.
3368 function _deprecated_function( $function, $version, $replacement = null ) {
3371 * Fires when a deprecated function is called.
3375 * @param string $function The function that was called.
3376 * @param string $replacement The function that should have been called.
3377 * @param string $version The version of WordPress that deprecated the function.
3379 do_action( 'deprecated_function_run', $function, $replacement, $version );
3382 * Filter whether to trigger an error for deprecated functions.
3386 * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3388 if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3389 if ( function_exists( '__' ) ) {
3390 if ( ! is_null( $replacement ) )
3391 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
3393 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3395 if ( ! is_null( $replacement ) )
3396 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
3398 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3404 * Mark a file as deprecated and inform when it has been used.
3406 * There is a hook deprecated_file_included that will be called that can be used
3407 * to get the backtrace up to what file and function included the deprecated
3410 * The current behavior is to trigger a user error if WP_DEBUG is true.
3412 * This function is to be used in every file that is deprecated.
3417 * @param string $file The file that was included.
3418 * @param string $version The version of WordPress that deprecated the file.
3419 * @param string $replacement Optional. The file that should have been included based on ABSPATH.
3421 * @param string $message Optional. A message regarding the change. Default empty.
3423 function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
3426 * Fires when a deprecated file is called.
3430 * @param string $file The file that was called.
3431 * @param string $replacement The file that should have been included based on ABSPATH.
3432 * @param string $version The version of WordPress that deprecated the file.
3433 * @param string $message A message regarding the change.
3435 do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
3438 * Filter whether to trigger an error for deprecated files.
3442 * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
3444 if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
3445 $message = empty( $message ) ? '' : ' ' . $message;
3446 if ( function_exists( '__' ) ) {
3447 if ( ! is_null( $replacement ) )
3448 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
3450 trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
3452 if ( ! is_null( $replacement ) )
3453 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
3455 trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
3460 * Mark a function argument as deprecated and inform when it has been used.
3462 * This function is to be used whenever a deprecated function argument is used.
3463 * Before this function is called, the argument must be checked for whether it was
3464 * used by comparing it to its default value or evaluating whether it is empty.
3467 * if ( ! empty( $deprecated ) ) {
3468 * _deprecated_argument( __FUNCTION__, '3.0' );
3472 * There is a hook deprecated_argument_run that will be called that can be used
3473 * to get the backtrace up to what file and function used the deprecated
3476 * The current behavior is to trigger a user error if WP_DEBUG is true.
3481 * @param string $function The function that was called.
3482 * @param string $version The version of WordPress that deprecated the argument used.
3483 * @param string $message Optional. A message regarding the change. Default null.
3485 function _deprecated_argument( $function, $version, $message = null ) {
3488 * Fires when a deprecated argument is called.
3492 * @param string $function The function that was called.
3493 * @param string $message A message regarding the change.
3494 * @param string $version The version of WordPress that deprecated the argument used.
3496 do_action( 'deprecated_argument_run', $function, $message, $version );
3499 * Filter whether to trigger an error for deprecated arguments.
3503 * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
3505 if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
3506 if ( function_exists( '__' ) ) {
3507 if ( ! is_null( $message ) )
3508 trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
3510 trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3512 if ( ! is_null( $message ) )
3513 trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
3515 trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3521 * Mark something as being incorrectly called.
3523 * There is a hook doing_it_wrong_run that will be called that can be used
3524 * to get the backtrace up to what file and function called the deprecated
3527 * The current behavior is to trigger a user error if WP_DEBUG is true.
3532 * @param string $function The function that was called.
3533 * @param string $message A message explaining what has been done incorrectly.
3534 * @param string $version The version of WordPress where the message was added.
3536 function _doing_it_wrong( $function, $message, $version ) {
3539 * Fires when the given function is being used incorrectly.
3543 * @param string $function The function that was called.
3544 * @param string $message A message explaining what has been done incorrectly.
3545 * @param string $version The version of WordPress where the message was added.
3547 do_action( 'doing_it_wrong_run', $function, $message, $version );
3550 * Filter whether to trigger an error for _doing_it_wrong() calls.
3554 * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
3556 if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
3557 if ( function_exists( '__' ) ) {
3558 $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
3559 $message .= ' ' . __( 'Please see <a href="https://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
3560 trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
3562 $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
3563 $message .= ' Please see <a href="https://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
3564 trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
3570 * Is the server running earlier than 1.5.0 version of lighttpd?
3574 * @return bool Whether the server is running lighttpd < 1.5.0.
3576 function is_lighttpd_before_150() {
3577 $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
3578 $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
3579 return 'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
3583 * Does the specified module exist in the Apache config?
3587 * @param string $mod The module, e.g. mod_rewrite.
3588 * @param bool $default Optional. The default return value if the module is not found. Default false.
3589 * @return bool Whether the specified module is loaded.
3591 function apache_mod_loaded($mod, $default = false) {
3597 if ( function_exists( 'apache_get_modules' ) ) {
3598 $mods = apache_get_modules();
3599 if ( in_array($mod, $mods) )
3601 } elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
3604 $phpinfo = ob_get_clean();
3605 if ( false !== strpos($phpinfo, $mod) )
3612 * Check if IIS 7+ supports pretty permalinks.
3616 * @return bool Whether IIS7 supports permalinks.
3618 function iis7_supports_permalinks() {
3621 $supports_permalinks = false;
3623 /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
3624 * easily update the xml configuration file, hence we just bail out and tell user that
3625 * pretty permalinks cannot be used.
3627 * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
3628 * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
3629 * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
3630 * via ISAPI then pretty permalinks will not work.
3632 $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( PHP_SAPI == 'cgi-fcgi' );
3636 * Filter whether IIS 7+ supports pretty permalinks.
3640 * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
3642 return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
3646 * File validates against allowed set of defined rules.
3648 * A return value of '1' means that the $file contains either '..' or './'. A
3649 * return value of '2' means that the $file contains ':' after the first
3650 * character. A return value of '3' means that the file is not in the allowed
3655 * @param string $file File path.
3656 * @param array $allowed_files List of allowed files.
3657 * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
3659 function validate_file( $file, $allowed_files = '' ) {
3660 if ( false !== strpos( $file, '..' ) )
3663 if ( false !== strpos( $file, './' ) )
3666 if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
3669 if (':' == substr( $file, 1, 1 ) )
3676 * Determine if SSL is used.
3680 * @return bool True if SSL, false if not used.
3683 if ( isset($_SERVER['HTTPS']) ) {
3684 if ( 'on' == strtolower($_SERVER['HTTPS']) )
3686 if ( '1' == $_SERVER['HTTPS'] )
3688 } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
3695 * Whether SSL login should be forced.
3699 * @see force_ssl_admin()
3701 * @param string|bool $force Optional Whether to force SSL login. Default null.
3702 * @return bool True if forced, false if not forced.
3704 function force_ssl_login( $force = null ) {
3705 return force_ssl_admin( $force );
3709 * Whether to force SSL used for the Administration Screens.
3713 * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
3714 * @return bool True if forced, false if not forced.
3716 function force_ssl_admin( $force = null ) {
3717 static $forced = false;
3719 if ( !is_null( $force ) ) {
3720 $old_forced = $forced;
3729 * Guess the URL for the site.
3731 * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
3736 * @return string The guessed URL.
3738 function wp_guess_url() {
3739 if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
3742 $abspath_fix = str_replace( '\\', '/', ABSPATH );
3743 $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
3745 // The request is for the admin
3746 if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
3747 $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
3749 // The request is for a file in ABSPATH
3750 } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
3751 // Strip off any file/query params in the path
3752 $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
3755 if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
3756 // Request is hitting a file inside ABSPATH
3757 $directory = str_replace( ABSPATH, '', $script_filename_dir );
3758 // Strip off the sub directory, and any file/query paramss
3759 $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
3760 } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
3761 // Request is hitting a file above ABSPATH
3762 $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
3763 // Strip off any file/query params from the path, appending the sub directory to the install
3764 $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
3766 $path = $_SERVER['REQUEST_URI'];
3770 $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
3771 $url = $schema . $_SERVER['HTTP_HOST'] . $path;
3774 return rtrim($url, '/');
3778 * Temporarily suspend cache additions.
3780 * Stops more data being added to the cache, but still allows cache retrieval.
3781 * This is useful for actions, such as imports, when a lot of data would otherwise
3782 * be almost uselessly added to the cache.
3784 * Suspension lasts for a single page load at most. Remember to call this
3785 * function again if you wish to re-enable cache adds earlier.
3789 * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
3790 * @return bool The current suspend setting
3792 function wp_suspend_cache_addition( $suspend = null ) {
3793 static $_suspend = false;
3795 if ( is_bool( $suspend ) )
3796 $_suspend = $suspend;
3802 * Suspend cache invalidation.
3804 * Turns cache invalidation on and off. Useful during imports where you don't wont to do
3805 * invalidations every time a post is inserted. Callers must be sure that what they are
3806 * doing won't lead to an inconsistent cache when invalidation is suspended.
3810 * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
3811 * @return bool The current suspend setting.
3813 function wp_suspend_cache_invalidation( $suspend = true ) {
3814 global $_wp_suspend_cache_invalidation;
3816 $current_suspend = $_wp_suspend_cache_invalidation;
3817 $_wp_suspend_cache_invalidation = $suspend;
3818 return $current_suspend;
3822 * Determine whether a site is the main site of the current network.
3826 * @param int $site_id Optional. Site ID to test. Defaults to current site.
3827 * Defaults to current site.
3828 * @return bool True if $site_id is the main site of the network, or if not
3829 * running Multisite.
3831 function is_main_site( $site_id = null ) {
3832 // This is the current network's information; 'site' is old terminology.
3833 global $current_site;
3835 if ( ! is_multisite() )
3839 $site_id = get_current_blog_id();
3841 return (int) $site_id === (int) $current_site->blog_id;
3845 * Determine whether a network is the main network of the Multisite install.
3849 * @param int $network_id Optional. Network ID to test. Defaults to current network.
3850 * @return bool True if $network_id is the main network, or if not running Multisite.
3852 function is_main_network( $network_id = null ) {
3855 if ( ! is_multisite() )
3858 $current_network_id = (int) get_current_site()->id;
3860 if ( ! $network_id )
3861 $network_id = $current_network_id;
3862 $network_id = (int) $network_id;
3864 if ( defined( 'PRIMARY_NETWORK_ID' ) )
3865 return $network_id === (int) PRIMARY_NETWORK_ID;
3867 if ( 1 === $current_network_id )
3868 return $network_id === $current_network_id;
3870 $primary_network_id = (int) wp_cache_get( 'primary_network_id', 'site-options' );
3872 if ( $primary_network_id )
3873 return $network_id === $primary_network_id;
3875 $primary_network_id = (int) $wpdb->get_var( "SELECT id FROM $wpdb->site ORDER BY id LIMIT 1" );
3876 wp_cache_add( 'primary_network_id', $primary_network_id, 'site-options' );
3878 return $network_id === $primary_network_id;
3882 * Determine whether global terms are enabled.
3886 * @return bool True if multisite and global terms enabled.
3888 function global_terms_enabled() {
3889 if ( ! is_multisite() )
3892 static $global_terms = null;
3893 if ( is_null( $global_terms ) ) {
3896 * Filter whether global terms are enabled.
3898 * Passing a non-null value to the filter will effectively short-circuit the function,
3899 * returning the value of the 'global_terms_enabled' site option instead.
3903 * @param null $anbled Whether global terms are enabled.
3905 $filter = apply_filters( 'global_terms_enabled', null );
3906 if ( ! is_null( $filter ) )
3907 $global_terms = (bool) $filter;
3909 $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
3911 return $global_terms;
3915 * gmt_offset modification for smart timezone handling.
3917 * Overrides the gmt_offset option if we have a timezone_string available.
3921 * @return float|bool Timezone GMT offset, false otherwise.
3923 function wp_timezone_override_offset() {
3924 if ( !$timezone_string = get_option( 'timezone_string' ) ) {
3928 $timezone_object = timezone_open( $timezone_string );
3929 $datetime_object = date_create();
3930 if ( false === $timezone_object || false === $datetime_object ) {
3933 return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
3937 * Sort-helper for timezones.
3946 function _wp_timezone_choice_usort_callback( $a, $b ) {
3947 // Don't use translated versions of Etc
3948 if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
3949 // Make the order of these more like the old dropdown
3950 if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3951 return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
3953 if ( 'UTC' === $a['city'] ) {
3954 if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
3959 if ( 'UTC' === $b['city'] ) {
3960 if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
3965 return strnatcasecmp( $a['city'], $b['city'] );
3967 if ( $a['t_continent'] == $b['t_continent'] ) {
3968 if ( $a['t_city'] == $b['t_city'] ) {
3969 return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
3971 return strnatcasecmp( $a['t_city'], $b['t_city'] );
3973 // Force Etc to the bottom of the list
3974 if ( 'Etc' === $a['continent'] ) {
3977 if ( 'Etc' === $b['continent'] ) {
3980 return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
3985 * Gives a nicely-formatted list of timezone strings.
3989 * @param string $selected_zone Selected timezone.
3992 function wp_timezone_choice( $selected_zone ) {
3993 static $mo_loaded = false;
3995 $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
3997 // Load translations for continents and cities
3998 if ( !$mo_loaded ) {
3999 $locale = get_locale();
4000 $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
4001 load_textdomain( 'continents-cities', $mofile );
4006 foreach ( timezone_identifiers_list() as $zone ) {
4007 $zone = explode( '/', $zone );
4008 if ( !in_array( $zone[0], $continents ) ) {
4012 // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
4014 0 => ( isset( $zone[0] ) && $zone[0] ),
4015 1 => ( isset( $zone[1] ) && $zone[1] ),
4016 2 => ( isset( $zone[2] ) && $zone[2] ),
4018 $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
4019 $exists[4] = ( $exists[1] && $exists[3] );
4020 $exists[5] = ( $exists[2] && $exists[3] );
4023 'continent' => ( $exists[0] ? $zone[0] : '' ),
4024 'city' => ( $exists[1] ? $zone[1] : '' ),
4025 'subcity' => ( $exists[2] ? $zone[2] : '' ),
4026 't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
4027 't_city' => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
4028 't_subcity' => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
4031 usort( $zonen, '_wp_timezone_choice_usort_callback' );
4033 $structure = array();
4035 if ( empty( $selected_zone ) ) {
4036 $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
4039 foreach ( $zonen as $key => $zone ) {
4040 // Build value in an array to join later
4041 $value = array( $zone['continent'] );
4043 if ( empty( $zone['city'] ) ) {
4044 // It's at the continent level (generally won't happen)
4045 $display = $zone['t_continent'];
4047 // It's inside a continent group
4049 // Continent optgroup
4050 if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
4051 $label = $zone['t_continent'];
4052 $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
4055 // Add the city to the value
4056 $value[] = $zone['city'];
4058 $display = $zone['t_city'];
4059 if ( !empty( $zone['subcity'] ) ) {
4060 // Add the subcity to the value
4061 $value[] = $zone['subcity'];
4062 $display .= ' - ' . $zone['t_subcity'];
4067 $value = join( '/', $value );
4069 if ( $value === $selected_zone ) {
4070 $selected = 'selected="selected" ';
4072 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
4074 // Close continent optgroup
4075 if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
4076 $structure[] = '</optgroup>';
4081 $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
4083 if ( 'UTC' === $selected_zone )
4084 $selected = 'selected="selected" ';
4085 $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
4086 $structure[] = '</optgroup>';
4088 // Do manual UTC offsets
4089 $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
4090 $offset_range = array (-12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5,
4091 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14);
4092 foreach ( $offset_range as $offset ) {
4094 $offset_name = '+' . $offset;
4096 $offset_name = (string) $offset;
4098 $offset_value = $offset_name;
4099 $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
4100 $offset_name = 'UTC' . $offset_name;
4101 $offset_value = 'UTC' . $offset_value;
4103 if ( $offset_value === $selected_zone )
4104 $selected = 'selected="selected" ';
4105 $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
4108 $structure[] = '</optgroup>';
4110 return join( "\n", $structure );
4114 * Strip close comment and close php tags from file headers used by WP.
4119 * @see https://core.trac.wordpress.org/ticket/8497
4121 * @param string $str Header comment to clean up.
4124 function _cleanup_header_comment( $str ) {
4125 return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
4129 * Permanently delete comments or posts of any type that have held a status
4130 * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
4132 * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
4136 function wp_scheduled_delete() {
4139 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
4141 $posts_to_delete = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
4143 foreach ( (array) $posts_to_delete as $post ) {
4144 $post_id = (int) $post['post_id'];
4148 $del_post = get_post($post_id);
4150 if ( !$del_post || 'trash' != $del_post->post_status ) {
4151 delete_post_meta($post_id, '_wp_trash_meta_status');
4152 delete_post_meta($post_id, '_wp_trash_meta_time');
4154 wp_delete_post($post_id);
4158 $comments_to_delete = $wpdb->get_results($wpdb->prepare("SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
4160 foreach ( (array) $comments_to_delete as $comment ) {
4161 $comment_id = (int) $comment['comment_id'];
4165 $del_comment = get_comment($comment_id);
4167 if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
4168 delete_comment_meta($comment_id, '_wp_trash_meta_time');
4169 delete_comment_meta($comment_id, '_wp_trash_meta_status');
4171 wp_delete_comment($comment_id);
4177 * Retrieve metadata from a file.
4179 * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
4180 * Each piece of metadata must be on its own line. Fields can not span multiple
4181 * lines, the value will get cut at the end of the first line.
4183 * If the file data is not within that first 8kiB, then the author should correct
4184 * their plugin file and move the data headers to the top.
4186 * @link https://codex.wordpress.org/File_Header
4190 * @param string $file Path to the file.
4191 * @param array $default_headers List of headers, in the format array('HeaderKey' => 'Header Name').
4192 * @param string $context Optional. If specified adds filter hook "extra_{$context}_headers".
4194 * @return array Array of file headers in `HeaderKey => Header Value` format.
4196 function get_file_data( $file, $default_headers, $context = '' ) {
4197 // We don't need to write to the file, so just open for reading.
4198 $fp = fopen( $file, 'r' );
4200 // Pull only the first 8kiB of the file in.
4201 $file_data = fread( $fp, 8192 );
4203 // PHP will close file handle, but we are good citizens.
4206 // Make sure we catch CR-only line endings.
4207 $file_data = str_replace( "\r", "\n", $file_data );
4210 * Filter extra file headers by context.
4212 * The dynamic portion of the hook name, `$context`, refers to
4213 * the context where extra headers might be loaded.
4217 * @param array $extra_context_headers Empty array by default.
4219 if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
4220 $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
4221 $all_headers = array_merge( $extra_headers, (array) $default_headers );
4223 $all_headers = $default_headers;
4226 foreach ( $all_headers as $field => $regex ) {
4227 if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
4228 $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
4230 $all_headers[ $field ] = '';
4233 return $all_headers;
4239 * Useful for returning true to filters easily.
4243 * @see __return_false()
4245 * @return bool True.
4247 function __return_true() {
4254 * Useful for returning false to filters easily.
4258 * @see __return_true()
4260 * @return bool False.
4262 function __return_false() {
4269 * Useful for returning 0 to filters easily.
4275 function __return_zero() {
4280 * Returns an empty array.
4282 * Useful for returning an empty array to filters easily.
4286 * @return array Empty array.
4288 function __return_empty_array() {
4295 * Useful for returning null to filters easily.
4299 * @return null Null value.
4301 function __return_null() {
4306 * Returns an empty string.
4308 * Useful for returning an empty string to filters easily.
4312 * @see __return_null()
4314 * @return string Empty string.
4316 function __return_empty_string() {
4321 * Send a HTTP header to disable content type sniffing in browsers which support it.
4325 * @see http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
4326 * @see http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
4328 function send_nosniff_header() {
4329 @header( 'X-Content-Type-Options: nosniff' );
4333 * Return a MySQL expression for selecting the week number based on the start_of_week option.
4338 * @param string $column Database column.
4339 * @return string SQL clause.
4341 function _wp_mysql_week( $column ) {
4342 switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
4344 return "WEEK( $column, 1 )";
4350 return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
4353 return "WEEK( $column, 0 )";
4358 * Find hierarchy loops using a callback function that maps object IDs to parent IDs.
4363 * @param callback $callback Function that accepts ( ID, $callback_args ) and outputs parent_ID.
4364 * @param int $start The ID to start the loop check at.
4365 * @param int $start_parent The parent_ID of $start to use instead of calling $callback( $start ).
4366 * Use null to always use $callback
4367 * @param array $callback_args Optional. Additional arguments to send to $callback.
4368 * @return array IDs of all members of loop.
4370 function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
4371 $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
4373 if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
4376 return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
4380 * Use the "The Tortoise and the Hare" algorithm to detect loops.
4382 * For every step of the algorithm, the hare takes two steps and the tortoise one.
4383 * If the hare ever laps the tortoise, there must be a loop.
4388 * @param callback $callback Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
4389 * @param int $start The ID to start the loop check at.
4390 * @param array $override Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
4391 * Default empty array.
4392 * @param array $callback_args Optional. Additional arguments to send to $callback. Default empty array.
4393 * @param bool $_return_loop Optional. Return loop members or just detect presence of loop? Only set
4394 * to true if you already know the given $start is part of a loop (otherwise
4395 * the returned array might include branches). Default false.
4396 * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
4399 function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
4400 $tortoise = $hare = $evanescent_hare = $start;
4403 // Set evanescent_hare to one past hare
4404 // Increment hare two steps
4408 ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
4410 ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
4412 if ( $_return_loop )
4413 $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
4415 // tortoise got lapped - must be a loop
4416 if ( $tortoise == $evanescent_hare || $tortoise == $hare )
4417 return $_return_loop ? $return : $tortoise;
4419 // Increment tortoise by one step
4420 $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
4427 * Send a HTTP header to limit rendering of pages to same origin iframes.
4431 * @see https://developer.mozilla.org/en/the_x-frame-options_response_header
4433 function send_frame_options_header() {
4434 @header( 'X-Frame-Options: SAMEORIGIN' );
4438 * Retrieve a list of protocols to allow in HTML attributes.
4445 * @return array Array of allowed protocols.
4447 function wp_allowed_protocols() {
4450 if ( empty( $protocols ) ) {
4451 $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
4454 * Filter the list of protocols allowed in HTML attributes.
4458 * @param array $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
4460 $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
4467 * Return a comma-separated string of functions that have been called to get
4468 * to the current point in code.
4472 * @see https://core.trac.wordpress.org/ticket/19589
4474 * @param string $ignore_class Optional. A class to ignore all function calls within - useful
4475 * when you want to just give info about the callee. Default null.
4476 * @param int $skip_frames Optional. A number of stack frames to skip - useful for unwinding
4477 * back to the source of the issue. Default 0.
4478 * @param bool $pretty Optional. Whether or not you want a comma separated string or raw
4479 * array returned. Default true.
4480 * @return string|array Either a string containing a reversed comma separated trace or an array
4481 * of individual calls.
4483 function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
4484 if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
4485 $trace = debug_backtrace( false );
4487 $trace = debug_backtrace();
4490 $check_class = ! is_null( $ignore_class );
4491 $skip_frames++; // skip this function
4493 foreach ( $trace as $call ) {
4494 if ( $skip_frames > 0 ) {
4496 } elseif ( isset( $call['class'] ) ) {
4497 if ( $check_class && $ignore_class == $call['class'] )
4498 continue; // Filter out calls
4500 $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
4502 if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
4503 $caller[] = "{$call['function']}('{$call['args'][0]}')";
4504 } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
4505 $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
4507 $caller[] = $call['function'];
4512 return join( ', ', array_reverse( $caller ) );
4518 * Retrieve ids that are not already present in the cache.
4523 * @param array $object_ids ID list.
4524 * @param string $cache_key The cache bucket to check against.
4526 * @return array List of ids not present in the cache.
4528 function _get_non_cached_ids( $object_ids, $cache_key ) {
4530 foreach ( $object_ids as $id ) {
4532 if ( !wp_cache_get( $id, $cache_key ) ) {
4541 * Test if the current device has the capability to upload files.
4546 * @return bool true|false Whether the device is able to upload files.
4548 function _device_can_upload() {
4549 if ( ! wp_is_mobile() )
4552 $ua = $_SERVER['HTTP_USER_AGENT'];
4554 if ( strpos($ua, 'iPhone') !== false
4555 || strpos($ua, 'iPad') !== false
4556 || strpos($ua, 'iPod') !== false ) {
4557 return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
4564 * Test if a given path is a stream URL
4566 * @param string $path The resource path or URL.
4567 * @return bool True if the path is a stream URL.
4569 function wp_is_stream( $path ) {
4570 $wrappers = stream_get_wrappers();
4571 $wrappers_re = '(' . join('|', $wrappers) . ')';
4573 return preg_match( "!^$wrappers_re://!", $path ) === 1;
4577 * Test if the supplied date is valid for the Gregorian calendar.
4583 * @param int $month Month number.
4584 * @param int $day Day number.
4585 * @param int $year Year number.
4586 * @param string $source_date The date to filter.
4587 * @return bool True if valid date, false if not valid date.
4589 function wp_checkdate( $month, $day, $year, $source_date ) {
4591 * Filter whether the given date is valid for the Gregorian calendar.
4595 * @param bool $checkdate Whether the given date is valid.
4596 * @param string $source_date Date to check.
4598 return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
4602 * Load the auth check for monitoring whether the user is still logged in.
4604 * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
4606 * This is disabled for certain screens where a login screen could cause an
4607 * inconvenient interruption. A filter called wp_auth_check_load can be used
4608 * for fine-grained control.
4612 function wp_auth_check_load() {
4613 if ( ! is_admin() && ! is_user_logged_in() )
4616 if ( defined( 'IFRAME_REQUEST' ) )
4619 $screen = get_current_screen();
4620 $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
4621 $show = ! in_array( $screen->id, $hidden );
4624 * Filter whether to load the authentication check.
4626 * Passing a falsey value to the filter will effectively short-circuit
4627 * loading the authentication check.
4631 * @param bool $show Whether to load the authentication check.
4632 * @param WP_Screen $screen The current screen object.
4634 if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
4635 wp_enqueue_style( 'wp-auth-check' );
4636 wp_enqueue_script( 'wp-auth-check' );
4638 add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
4639 add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
4644 * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
4648 function wp_auth_check_html() {
4649 $login_url = wp_login_url();
4650 $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
4651 $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
4654 * Filter whether the authentication check originated at the same domain.
4658 * @param bool $same_domain Whether the authentication check originated at the same domain.
4660 $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
4661 $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
4664 <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
4665 <div id="wp-auth-check-bg"></div>
4666 <div id="wp-auth-check">
4667 <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
4670 if ( $same_domain ) {
4672 <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
4677 <div class="wp-auth-fallback">
4678 <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
4679 <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
4680 <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
4688 * Check whether a user is still logged in, for the heartbeat.
4690 * Send a result that shows a log-in box if the user is no longer logged in,
4691 * or if their cookie is within the grace period.
4695 * @param array|object $response The Heartbeat response object or array.
4696 * @return array|object $response The Heartbeat response object or array with 'wp-auth-check'
4699 function wp_auth_check( $response ) {
4700 $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
4705 * Return RegEx body to liberally match an opening HTML tag.
4707 * Matches an opening HTML tag that:
4708 * 1. Is self-closing or
4709 * 2. Has no body but has a closing tag of the same name or
4710 * 3. Contains a body and a closing tag of the same name
4712 * Note: this RegEx does not balance inner tags and does not attempt
4713 * to produce valid HTML
4717 * @param string $tag An HTML tag name. Example: 'video'.
4718 * @return string Tag RegEx.
4720 function get_tag_regex( $tag ) {
4721 if ( empty( $tag ) )
4723 return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
4727 * Retrieve a canonical form of the provided charset appropriate for passing to PHP
4728 * functions such as htmlspecialchars() and charset html attributes.
4733 * @see https://core.trac.wordpress.org/ticket/23688
4735 * @param string $charset A charset name.
4736 * @return string The canonical form of the charset.
4738 function _canonical_charset( $charset ) {
4739 if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
4740 'UTF8' === $charset )
4743 if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
4744 'iso8859-1' === $charset || 'ISO8859-1' === $charset )
4745 return 'ISO-8859-1';
4751 * Set the mbstring internal encoding to a binary safe encoding when func_overload
4754 * When mbstring.func_overload is in use for multi-byte encodings, the results from
4755 * strlen() and similar functions respect the utf8 characters, causing binary data
4756 * to return incorrect lengths.
4758 * This function overrides the mbstring encoding to a binary-safe encoding, and
4759 * resets it to the users expected encoding afterwards through the
4760 * `reset_mbstring_encoding` function.
4762 * It is safe to recursively call this function, however each
4763 * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
4764 * of `reset_mbstring_encoding()` calls.
4768 * @see reset_mbstring_encoding()
4770 * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
4773 function mbstring_binary_safe_encoding( $reset = false ) {
4774 static $encodings = array();
4775 static $overloaded = null;
4777 if ( is_null( $overloaded ) )
4778 $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
4780 if ( false === $overloaded )
4784 $encoding = mb_internal_encoding();
4785 array_push( $encodings, $encoding );
4786 mb_internal_encoding( 'ISO-8859-1' );
4789 if ( $reset && $encodings ) {
4790 $encoding = array_pop( $encodings );
4791 mb_internal_encoding( $encoding );
4796 * Reset the mbstring internal encoding to a users previously set encoding.
4798 * @see mbstring_binary_safe_encoding()
4802 function reset_mbstring_encoding() {
4803 mbstring_binary_safe_encoding( true );
4807 * Filter/validate a variable as a boolean.
4809 * Alternative to `filter_var( $var, FILTER_VALIDATE_BOOLEAN )`.
4813 * @param mixed $var Boolean value to validate.
4814 * @return bool Whether the value is validated.
4816 function wp_validate_boolean( $var ) {
4817 if ( is_bool( $var ) ) {
4821 if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
4833 * @param string $file The path to the file to delete.
4835 function wp_delete_file( $file ) {
4837 * Filter the path of the file to delete.
4841 * @param string $medium Path to the file to delete.
4843 $delete = apply_filters( 'wp_delete_file', $file );
4844 if ( ! empty( $delete ) ) {