| [ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Main WordPress API 4 * 5 * @package WordPress 6 */ 7 8 require ( ABSPATH . WPINC . '/option.php' ); 9 10 /** 11 * Converts MySQL DATETIME field to user specified date format. 12 * 13 * If $dateformatstring has 'G' value, then gmmktime() function will be used to 14 * make the time. If $dateformatstring is set to 'U', then mktime() function 15 * will be used to make the time. 16 * 17 * The $translate will only be used, if it is set to true and it is by default 18 * and if the $wp_locale object has the month and weekday set. 19 * 20 * @since 0.71 21 * 22 * @param string $dateformatstring Either 'G', 'U', or php date format. 23 * @param string $mysqlstring Time from mysql DATETIME field. 24 * @param bool $translate Optional. Default is true. Will switch format to locale. 25 * @return string Date formatted by $dateformatstring or locale (if available). 26 */ 27 function mysql2date( $dateformatstring, $mysqlstring, $translate = true ) { 28 $m = $mysqlstring; 29 if ( empty( $m ) ) 30 return false; 31 32 if ( 'G' == $dateformatstring ) 33 return strtotime( $m . ' +0000' ); 34 35 $i = strtotime( $m ); 36 37 if ( 'U' == $dateformatstring ) 38 return $i; 39 40 if ( $translate ) 41 return date_i18n( $dateformatstring, $i ); 42 else 43 return date( $dateformatstring, $i ); 44 } 45 46 /** 47 * Retrieve the current time based on specified type. 48 * 49 * The 'mysql' type will return the time in the format for MySQL DATETIME field. 50 * The 'timestamp' type will return the current timestamp. 51 * 52 * If $gmt is set to either '1' or 'true', then both types will use GMT time. 53 * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option. 54 * 55 * @since 1.0.0 56 * 57 * @param string $type Either 'mysql' or 'timestamp'. 58 * @param int|bool $gmt Optional. Whether to use GMT timezone. Default is false. 59 * @return int|string String if $type is 'gmt', int if $type is 'timestamp'. 60 */ 61 function current_time( $type, $gmt = 0 ) { 62 switch ( $type ) { 63 case 'mysql': 64 return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * 3600 ) ) ); 65 break; 66 case 'timestamp': 67 return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * 3600 ); 68 break; 69 } 70 } 71 72 /** 73 * Retrieve the date in localized format, based on timestamp. 74 * 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. 78 * 79 * @since 0.71 80 * 81 * @param string $dateformatstring Format to display the date. 82 * @param int $unixtimestamp Optional. Unix timestamp. 83 * @param bool $gmt Optional, default is false. Whether to convert to GMT for time. 84 * @return string The date, translated if locale specifies it. 85 */ 86 function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) { 87 global $wp_locale; 88 $i = $unixtimestamp; 89 90 if ( false === $i ) { 91 if ( ! $gmt ) 92 $i = current_time( 'timestamp' ); 93 else 94 $i = time(); 95 // we should not let date() interfere with our 96 // specially computed timestamp 97 $gmt = true; 98 } 99 100 // store original value for language with untypical grammars 101 // see http://core.trac.wordpress.org/ticket/9396 102 $req_format = $dateformatstring; 103 104 $datefunc = $gmt? 'gmdate' : 'date'; 105 106 if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) { 107 $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) ); 108 $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth ); 109 $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) ); 110 $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday ); 111 $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) ); 112 $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) ); 113 $dateformatstring = ' '.$dateformatstring; 114 $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring ); 115 $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring ); 116 $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring ); 117 $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring ); 118 $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring ); 119 $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring ); 120 121 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); 122 } 123 $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' ); 124 $timezone_formats_re = implode( '|', $timezone_formats ); 125 if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) { 126 $timezone_string = get_option( 'timezone_string' ); 127 if ( $timezone_string ) { 128 $timezone_object = timezone_open( $timezone_string ); 129 $date_object = date_create( null, $timezone_object ); 130 foreach( $timezone_formats as $timezone_format ) { 131 if ( false !== strpos( $dateformatstring, $timezone_format ) ) { 132 $formatted = date_format( $date_object, $timezone_format ); 133 $dateformatstring = ' '.$dateformatstring; 134 $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring ); 135 $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 ); 136 } 137 } 138 } 139 } 140 $j = @$datefunc( $dateformatstring, $i ); 141 // allow plugins to redo this entirely for languages with untypical grammars 142 $j = apply_filters('date_i18n', $j, $req_format, $i, $gmt); 143 return $j; 144 } 145 146 /** 147 * Convert integer number to format based on the locale. 148 * 149 * @since 2.3.0 150 * 151 * @param int $number The number to convert based on locale. 152 * @param int $decimals Precision of the number of decimal places. 153 * @return string Converted number in string format. 154 */ 155 function number_format_i18n( $number, $decimals = 0 ) { 156 global $wp_locale; 157 $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] ); 158 return apply_filters( 'number_format_i18n', $formatted ); 159 } 160 161 /** 162 * Convert number of bytes largest unit bytes will fit into. 163 * 164 * It is easier to read 1kB than 1024 bytes and 1MB than 1048576 bytes. Converts 165 * number of bytes to human readable number by taking the number of that unit 166 * that the bytes will go into it. Supports TB value. 167 * 168 * Please note that integers in PHP are limited to 32 bits, unless they are on 169 * 64 bit architecture, then they have 64 bit size. If you need to place the 170 * larger size then what PHP integer type will hold, then use a string. It will 171 * be converted to a double, which should always have 64 bit length. 172 * 173 * Technically the correct unit names for powers of 1024 are KiB, MiB etc. 174 * @link http://en.wikipedia.org/wiki/Byte 175 * 176 * @since 2.3.0 177 * 178 * @param int|string $bytes Number of bytes. Note max integer size for integers. 179 * @param int $decimals Precision of number of decimal places. Deprecated. 180 * @return bool|string False on failure. Number string on success. 181 */ 182 function size_format( $bytes, $decimals = 0 ) { 183 $quant = array( 184 // ========================= Origin ==== 185 'TB' => 1099511627776, // pow( 1024, 4) 186 'GB' => 1073741824, // pow( 1024, 3) 187 'MB' => 1048576, // pow( 1024, 2) 188 'kB' => 1024, // pow( 1024, 1) 189 'B ' => 1, // pow( 1024, 0) 190 ); 191 foreach ( $quant as $unit => $mag ) 192 if ( doubleval($bytes) >= $mag ) 193 return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit; 194 195 return false; 196 } 197 198 /** 199 * Get the week start and end from the datetime or date string from mysql. 200 * 201 * @since 0.71 202 * 203 * @param string $mysqlstring Date or datetime field type from mysql. 204 * @param int $start_of_week Optional. Start of the week as an integer. 205 * @return array Keys are 'start' and 'end'. 206 */ 207 function get_weekstartend( $mysqlstring, $start_of_week = '' ) { 208 $my = substr( $mysqlstring, 0, 4 ); // Mysql string Year 209 $mm = substr( $mysqlstring, 8, 2 ); // Mysql string Month 210 $md = substr( $mysqlstring, 5, 2 ); // Mysql string day 211 $day = mktime( 0, 0, 0, $md, $mm, $my ); // The timestamp for mysqlstring day. 212 $weekday = date( 'w', $day ); // The day of the week from the timestamp 213 if ( !is_numeric($start_of_week) ) 214 $start_of_week = get_option( 'start_of_week' ); 215 216 if ( $weekday < $start_of_week ) 217 $weekday += 7; 218 219 $start = $day - 86400 * ( $weekday - $start_of_week ); // The most recent week start day on or before $day 220 $end = $start + 604799; // $start + 7 days - 1 second 221 return compact( 'start', 'end' ); 222 } 223 224 /** 225 * Unserialize value only if it was serialized. 226 * 227 * @since 2.0.0 228 * 229 * @param string $original Maybe unserialized original, if is needed. 230 * @return mixed Unserialized data can be any type. 231 */ 232 function maybe_unserialize( $original ) { 233 if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in 234 return @unserialize( $original ); 235 return $original; 236 } 237 238 /** 239 * Check value to find if it was serialized. 240 * 241 * If $data is not an string, then returned value will always be false. 242 * Serialized data is always a string. 243 * 244 * @since 2.0.5 245 * 246 * @param mixed $data Value to check to see if was serialized. 247 * @return bool False if not serialized and true if it was. 248 */ 249 function is_serialized( $data ) { 250 // if it isn't a string, it isn't serialized 251 if ( ! is_string( $data ) ) 252 return false; 253 $data = trim( $data ); 254 if ( 'N;' == $data ) 255 return true; 256 $length = strlen( $data ); 257 if ( $length < 4 ) 258 return false; 259 if ( ':' !== $data[1] ) 260 return false; 261 $lastc = $data[$length-1]; 262 if ( ';' !== $lastc && '}' !== $lastc ) 263 return false; 264 $token = $data[0]; 265 switch ( $token ) { 266 case 's' : 267 if ( '"' !== $data[$length-2] ) 268 return false; 269 case 'a' : 270 case 'O' : 271 return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data ); 272 case 'b' : 273 case 'i' : 274 case 'd' : 275 return (bool) preg_match( "/^{$token}:[0-9.E-]+;\$/", $data ); 276 } 277 return false; 278 } 279 280 /** 281 * Check whether serialized data is of string type. 282 * 283 * @since 2.0.5 284 * 285 * @param mixed $data Serialized data 286 * @return bool False if not a serialized string, true if it is. 287 */ 288 function is_serialized_string( $data ) { 289 // if it isn't a string, it isn't a serialized string 290 if ( !is_string( $data ) ) 291 return false; 292 $data = trim( $data ); 293 $length = strlen( $data ); 294 if ( $length < 4 ) 295 return false; 296 elseif ( ':' !== $data[1] ) 297 return false; 298 elseif ( ';' !== $data[$length-1] ) 299 return false; 300 elseif ( $data[0] !== 's' ) 301 return false; 302 elseif ( '"' !== $data[$length-2] ) 303 return false; 304 else 305 return true; 306 } 307 308 /** 309 * Serialize data, if needed. 310 * 311 * @since 2.0.5 312 * 313 * @param mixed $data Data that might be serialized. 314 * @return mixed A scalar data 315 */ 316 function maybe_serialize( $data ) { 317 if ( is_array( $data ) || is_object( $data ) ) 318 return serialize( $data ); 319 320 // Double serialization is required for backward compatibility. 321 // See http://core.trac.wordpress.org/ticket/12930 322 if ( is_serialized( $data ) ) 323 return serialize( $data ); 324 325 return $data; 326 } 327 328 /** 329 * Retrieve post title from XMLRPC XML. 330 * 331 * If the title element is not part of the XML, then the default post title from 332 * the $post_default_title will be used instead. 333 * 334 * @package WordPress 335 * @subpackage XMLRPC 336 * @since 0.71 337 * 338 * @global string $post_default_title Default XMLRPC post title. 339 * 340 * @param string $content XMLRPC XML Request content 341 * @return string Post title 342 */ 343 function xmlrpc_getposttitle( $content ) { 344 global $post_default_title; 345 if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) { 346 $post_title = $matchtitle[1]; 347 } else { 348 $post_title = $post_default_title; 349 } 350 return $post_title; 351 } 352 353 /** 354 * Retrieve the post category or categories from XMLRPC XML. 355 * 356 * If the category element is not found, then the default post category will be 357 * used. The return type then would be what $post_default_category. If the 358 * category is found, then it will always be an array. 359 * 360 * @package WordPress 361 * @subpackage XMLRPC 362 * @since 0.71 363 * 364 * @global string $post_default_category Default XMLRPC post category. 365 * 366 * @param string $content XMLRPC XML Request content 367 * @return string|array List of categories or category name. 368 */ 369 function xmlrpc_getpostcategory( $content ) { 370 global $post_default_category; 371 if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) { 372 $post_category = trim( $matchcat[1], ',' ); 373 $post_category = explode( ',', $post_category ); 374 } else { 375 $post_category = $post_default_category; 376 } 377 return $post_category; 378 } 379 380 /** 381 * XMLRPC XML content without title and category elements. 382 * 383 * @package WordPress 384 * @subpackage XMLRPC 385 * @since 0.71 386 * 387 * @param string $content XMLRPC XML Request content 388 * @return string XMLRPC XML Request content without title and category elements. 389 */ 390 function xmlrpc_removepostdata( $content ) { 391 $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content ); 392 $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content ); 393 $content = trim( $content ); 394 return $content; 395 } 396 397 /** 398 * Open the file handle for debugging. 399 * 400 * This function is used for XMLRPC feature, but it is general purpose enough 401 * to be used in anywhere. 402 * 403 * @see fopen() for mode options. 404 * @package WordPress 405 * @subpackage Debug 406 * @since 0.71 407 * @uses $debug Used for whether debugging is enabled. 408 * 409 * @param string $filename File path to debug file. 410 * @param string $mode Same as fopen() mode parameter. 411 * @return bool|resource File handle. False on failure. 412 */ 413 function debug_fopen( $filename, $mode ) { 414 global $debug; 415 if ( 1 == $debug ) { 416 $fp = fopen( $filename, $mode ); 417 return $fp; 418 } else { 419 return false; 420 } 421 } 422 423 /** 424 * Write contents to the file used for debugging. 425 * 426 * Technically, this can be used to write to any file handle when the global 427 * $debug is set to 1 or true. 428 * 429 * @package WordPress 430 * @subpackage Debug 431 * @since 0.71 432 * @uses $debug Used for whether debugging is enabled. 433 * 434 * @param resource $fp File handle for debugging file. 435 * @param string $string Content to write to debug file. 436 */ 437 function debug_fwrite( $fp, $string ) { 438 global $debug; 439 if ( 1 == $debug ) 440 fwrite( $fp, $string ); 441 } 442 443 /** 444 * Close the debugging file handle. 445 * 446 * Technically, this can be used to close any file handle when the global $debug 447 * is set to 1 or true. 448 * 449 * @package WordPress 450 * @subpackage Debug 451 * @since 0.71 452 * @uses $debug Used for whether debugging is enabled. 453 * 454 * @param resource $fp Debug File handle. 455 */ 456 function debug_fclose( $fp ) { 457 global $debug; 458 if ( 1 == $debug ) 459 fclose( $fp ); 460 } 461 462 /** 463 * Check content for video and audio links to add as enclosures. 464 * 465 * Will not add enclosures that have already been added and will 466 * remove enclosures that are no longer in the post. This is called as 467 * pingbacks and trackbacks. 468 * 469 * @package WordPress 470 * @since 1.5.0 471 * 472 * @uses $wpdb 473 * 474 * @param string $content Post Content 475 * @param int $post_ID Post ID 476 */ 477 function do_enclose( $content, $post_ID ) { 478 global $wpdb; 479 480 //TODO: Tidy this ghetto code up and make the debug code optional 481 include_once ( ABSPATH . WPINC . '/class-IXR.php' ); 482 483 $log = debug_fopen( ABSPATH . 'enclosures.log', 'a' ); 484 $post_links = array(); 485 debug_fwrite( $log, 'BEGIN ' . date( 'YmdHis', time() ) . "\n" ); 486 487 $pung = get_enclosed( $post_ID ); 488 489 $ltrs = '\w'; 490 $gunk = '/#~:.?+=&%@!\-'; 491 $punc = '.:?\-'; 492 $any = $ltrs . $gunk . $punc; 493 494 preg_match_all( "{\b http : [$any] +? (?= [$punc] * [^$any] | $)}x", $content, $post_links_temp ); 495 496 debug_fwrite( $log, 'Post contents:' ); 497 debug_fwrite( $log, $content . "\n" ); 498 499 foreach ( $pung as $link_test ) { 500 if ( !in_array( $link_test, $post_links_temp[0] ) ) { // link no longer in post 501 $mid = $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, like_escape( $link_test ) . '%') ); 502 do_action( 'delete_postmeta', $mid ); 503 $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id IN(%s)", implode( ',', $mid ) ) ); 504 do_action( 'deleted_postmeta', $mid ); 505 } 506 } 507 508 foreach ( (array) $post_links_temp[0] as $link_test ) { 509 if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already 510 $test = @parse_url( $link_test ); 511 if ( false === $test ) 512 continue; 513 if ( isset( $test['query'] ) ) 514 $post_links[] = $link_test; 515 elseif ( isset($test['path']) && ( $test['path'] != '/' ) && ($test['path'] != '' ) ) 516 $post_links[] = $link_test; 517 } 518 } 519 520 foreach ( (array) $post_links as $url ) { 521 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, like_escape( $url ) . '%' ) ) ) { 522 523 if ( $headers = wp_get_http_headers( $url) ) { 524 $len = (int) $headers['content-length']; 525 $type = $headers['content-type']; 526 $allowed_types = array( 'video', 'audio' ); 527 528 // Check to see if we can figure out the mime type from 529 // the extension 530 $url_parts = @parse_url( $url ); 531 if ( false !== $url_parts ) { 532 $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION ); 533 if ( !empty( $extension ) ) { 534 foreach ( get_allowed_mime_types( ) as $exts => $mime ) { 535 if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) { 536 $type = $mime; 537 break; 538 } 539 } 540 } 541 } 542 543 if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) { 544 $meta_value = "$url\n$len\n$type\n"; 545 $wpdb->insert($wpdb->postmeta, array('post_id' => $post_ID, 'meta_key' => 'enclosure', 'meta_value' => $meta_value) ); 546 do_action( 'added_postmeta', $wpdb->insert_id, $post_ID, 'enclosure', $meta_value ); 547 } 548 } 549 } 550 } 551 } 552 553 /** 554 * Perform a HTTP HEAD or GET request. 555 * 556 * If $file_path is a writable filename, this will do a GET request and write 557 * the file to that path. 558 * 559 * @since 2.5.0 560 * 561 * @param string $url URL to fetch. 562 * @param string|bool $file_path Optional. File path to write request to. 563 * @param int $red (private) The number of Redirects followed, Upon 5 being hit, returns false. 564 * @return bool|string False on failure and string of headers if HEAD request. 565 */ 566 function wp_get_http( $url, $file_path = false, $red = 1 ) { 567 @set_time_limit( 60 ); 568 569 if ( $red > 5 ) 570 return false; 571 572 $options = array(); 573 $options['redirection'] = 5; 574 575 if ( false == $file_path ) 576 $options['method'] = 'HEAD'; 577 else 578 $options['method'] = 'GET'; 579 580 $response = wp_remote_request($url, $options); 581 582 if ( is_wp_error( $response ) ) 583 return false; 584 585 $headers = wp_remote_retrieve_headers( $response ); 586 $headers['response'] = wp_remote_retrieve_response_code( $response ); 587 588 // WP_HTTP no longer follows redirects for HEAD requests. 589 if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) { 590 return wp_get_http( $headers['location'], $file_path, ++$red ); 591 } 592 593 if ( false == $file_path ) 594 return $headers; 595 596 // GET request - write it to the supplied filename 597 $out_fp = fopen($file_path, 'w'); 598 if ( !$out_fp ) 599 return $headers; 600 601 fwrite( $out_fp, wp_remote_retrieve_body( $response ) ); 602 fclose($out_fp); 603 clearstatcache(); 604 605 return $headers; 606 } 607 608 /** 609 * Retrieve HTTP Headers from URL. 610 * 611 * @since 1.5.1 612 * 613 * @param string $url 614 * @param bool $deprecated Not Used. 615 * @return bool|string False on failure, headers on success. 616 */ 617 function wp_get_http_headers( $url, $deprecated = false ) { 618 if ( !empty( $deprecated ) ) 619 _deprecated_argument( __FUNCTION__, '2.7' ); 620 621 $response = wp_remote_head( $url ); 622 623 if ( is_wp_error( $response ) ) 624 return false; 625 626 return wp_remote_retrieve_headers( $response ); 627 } 628 629 /** 630 * Whether today is a new day. 631 * 632 * @since 0.71 633 * @uses $day Today 634 * @uses $previousday Previous day 635 * 636 * @return int 1 when new day, 0 if not a new day. 637 */ 638 function is_new_day() { 639 global $currentday, $previousday; 640 if ( $currentday != $previousday ) 641 return 1; 642 else 643 return 0; 644 } 645 646 /** 647 * Build URL query based on an associative and, or indexed array. 648 * 649 * This is a convenient function for easily building url queries. It sets the 650 * separator to '&' and uses _http_build_query() function. 651 * 652 * @see _http_build_query() Used to build the query 653 * @link http://us2.php.net/manual/en/function.http-build-query.php more on what 654 * http_build_query() does. 655 * 656 * @since 2.3.0 657 * 658 * @param array $data URL-encode key/value pairs. 659 * @return string URL encoded string 660 */ 661 function build_query( $data ) { 662 return _http_build_query( $data, null, '&', '', false ); 663 } 664 665 // from php.net (modified by Mark Jaquith to behave like the native PHP5 function) 666 function _http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=true) { 667 $ret = array(); 668 669 foreach ( (array) $data as $k => $v ) { 670 if ( $urlencode) 671 $k = urlencode($k); 672 if ( is_int($k) && $prefix != null ) 673 $k = $prefix.$k; 674 if ( !empty($key) ) 675 $k = $key . '%5B' . $k . '%5D'; 676 if ( $v === null ) 677 continue; 678 elseif ( $v === FALSE ) 679 $v = '0'; 680 681 if ( is_array($v) || is_object($v) ) 682 array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode)); 683 elseif ( $urlencode ) 684 array_push($ret, $k.'='.urlencode($v)); 685 else 686 array_push($ret, $k.'='.$v); 687 } 688 689 if ( null === $sep ) 690 $sep = ini_get('arg_separator.output'); 691 692 return implode($sep, $ret); 693 } 694 695 /** 696 * Retrieve a modified URL query string. 697 * 698 * You can rebuild the URL and append a new query variable to the URL query by 699 * using this function. You can also retrieve the full URL with query data. 700 * 701 * Adding a single key & value or an associative array. Setting a key value to 702 * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER 703 * value. Additional values provided are expected to be encoded appropriately 704 * with urlencode() or rawurlencode(). 705 * 706 * @since 1.5.0 707 * 708 * @param mixed $param1 Either newkey or an associative_array 709 * @param mixed $param2 Either newvalue or oldquery or uri 710 * @param mixed $param3 Optional. Old query or uri 711 * @return string New URL query string. 712 */ 713 function add_query_arg() { 714 $ret = ''; 715 if ( is_array( func_get_arg(0) ) ) { 716 if ( @func_num_args() < 2 || false === @func_get_arg( 1 ) ) 717 $uri = $_SERVER['REQUEST_URI']; 718 else 719 $uri = @func_get_arg( 1 ); 720 } else { 721 if ( @func_num_args() < 3 || false === @func_get_arg( 2 ) ) 722 $uri = $_SERVER['REQUEST_URI']; 723 else 724 $uri = @func_get_arg( 2 ); 725 } 726 727 if ( $frag = strstr( $uri, '#' ) ) 728 $uri = substr( $uri, 0, -strlen( $frag ) ); 729 else 730 $frag = ''; 731 732 if ( preg_match( '|^https?://|i', $uri, $matches ) ) { 733 $protocol = $matches[0]; 734 $uri = substr( $uri, strlen( $protocol ) ); 735 } else { 736 $protocol = ''; 737 } 738 739 if ( strpos( $uri, '?' ) !== false ) { 740 $parts = explode( '?', $uri, 2 ); 741 if ( 1 == count( $parts ) ) { 742 $base = '?'; 743 $query = $parts[0]; 744 } else { 745 $base = $parts[0] . '?'; 746 $query = $parts[1]; 747 } 748 } elseif ( !empty( $protocol ) || strpos( $uri, '=' ) === false ) { 749 $base = $uri . '?'; 750 $query = ''; 751 } else { 752 $base = ''; 753 $query = $uri; 754 } 755 756 wp_parse_str( $query, $qs ); 757 $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string 758 if ( is_array( func_get_arg( 0 ) ) ) { 759 $kayvees = func_get_arg( 0 ); 760 $qs = array_merge( $qs, $kayvees ); 761 } else { 762 $qs[func_get_arg( 0 )] = func_get_arg( 1 ); 763 } 764 765 foreach ( (array) $qs as $k => $v ) { 766 if ( $v === false ) 767 unset( $qs[$k] ); 768 } 769 770 $ret = build_query( $qs ); 771 $ret = trim( $ret, '?' ); 772 $ret = preg_replace( '#=(&|$)#', '$1', $ret ); 773 $ret = $protocol . $base . $ret . $frag; 774 $ret = rtrim( $ret, '?' ); 775 return $ret; 776 } 777 778 /** 779 * Removes an item or list from the query string. 780 * 781 * @since 1.5.0 782 * 783 * @param string|array $key Query key or keys to remove. 784 * @param bool $query When false uses the $_SERVER value. 785 * @return string New URL query string. 786 */ 787 function remove_query_arg( $key, $query=false ) { 788 if ( is_array( $key ) ) { // removing multiple keys 789 foreach ( $key as $k ) 790 $query = add_query_arg( $k, false, $query ); 791 return $query; 792 } 793 return add_query_arg( $key, false, $query ); 794 } 795 796 /** 797 * Walks the array while sanitizing the contents. 798 * 799 * @since 0.71 800 * 801 * @param array $array Array to used to walk while sanitizing contents. 802 * @return array Sanitized $array. 803 */ 804 function add_magic_quotes( $array ) { 805 foreach ( (array) $array as $k => $v ) { 806 if ( is_array( $v ) ) { 807 $array[$k] = add_magic_quotes( $v ); 808 } else { 809 $array[$k] = addslashes( $v ); 810 } 811 } 812 return $array; 813 } 814 815 /** 816 * HTTP request for URI to retrieve content. 817 * 818 * @since 1.5.1 819 * @uses wp_remote_get() 820 * 821 * @param string $uri URI/URL of web page to retrieve. 822 * @return bool|string HTTP content. False on failure. 823 */ 824 function wp_remote_fopen( $uri ) { 825 $parsed_url = @parse_url( $uri ); 826 827 if ( !$parsed_url || !is_array( $parsed_url ) ) 828 return false; 829 830 $options = array(); 831 $options['timeout'] = 10; 832 833 $response = wp_remote_get( $uri, $options ); 834 835 if ( is_wp_error( $response ) ) 836 return false; 837 838 return wp_remote_retrieve_body( $response ); 839 } 840 841 /** 842 * Set up the WordPress query. 843 * 844 * @since 2.0.0 845 * 846 * @param string $query_vars Default WP_Query arguments. 847 */ 848 function wp( $query_vars = '' ) { 849 global $wp, $wp_query, $wp_the_query; 850 $wp->main( $query_vars ); 851 852 if ( !isset($wp_the_query) ) 853 $wp_the_query = $wp_query; 854 } 855 856 /** 857 * Retrieve the description for the HTTP status. 858 * 859 * @since 2.3.0 860 * 861 * @param int $code HTTP status code. 862 * @return string Empty string if not found, or description if found. 863 */ 864 function get_status_header_desc( $code ) { 865 global $wp_header_to_desc; 866 867 $code = absint( $code ); 868 869 if ( !isset( $wp_header_to_desc ) ) { 870 $wp_header_to_desc = array( 871 100 => 'Continue', 872 101 => 'Switching Protocols', 873 102 => 'Processing', 874 875 200 => 'OK', 876 201 => 'Created', 877 202 => 'Accepted', 878 203 => 'Non-Authoritative Information', 879 204 => 'No Content', 880 205 => 'Reset Content', 881 206 => 'Partial Content', 882 207 => 'Multi-Status', 883 226 => 'IM Used', 884 885 300 => 'Multiple Choices', 886 301 => 'Moved Permanently', 887 302 => 'Found', 888 303 => 'See Other', 889 304 => 'Not Modified', 890 305 => 'Use Proxy', 891 306 => 'Reserved', 892 307 => 'Temporary Redirect', 893 894 400 => 'Bad Request', 895 401 => 'Unauthorized', 896 402 => 'Payment Required', 897 403 => 'Forbidden', 898 404 => 'Not Found', 899 405 => 'Method Not Allowed', 900 406 => 'Not Acceptable', 901 407 => 'Proxy Authentication Required', 902 408 => 'Request Timeout', 903 409 => 'Conflict', 904 410 => 'Gone', 905 411 => 'Length Required', 906 412 => 'Precondition Failed', 907 413 => 'Request Entity Too Large', 908 414 => 'Request-URI Too Long', 909 415 => 'Unsupported Media Type', 910 416 => 'Requested Range Not Satisfiable', 911 417 => 'Expectation Failed', 912 422 => 'Unprocessable Entity', 913 423 => 'Locked', 914 424 => 'Failed Dependency', 915 426 => 'Upgrade Required', 916 917 500 => 'Internal Server Error', 918 501 => 'Not Implemented', 919 502 => 'Bad Gateway', 920 503 => 'Service Unavailable', 921 504 => 'Gateway Timeout', 922 505 => 'HTTP Version Not Supported', 923 506 => 'Variant Also Negotiates', 924 507 => 'Insufficient Storage', 925 510 => 'Not Extended' 926 ); 927 } 928 929 if ( isset( $wp_header_to_desc[$code] ) ) 930 return $wp_header_to_desc[$code]; 931 else 932 return ''; 933 } 934 935 /** 936 * Set HTTP status header. 937 * 938 * @since 2.0.0 939 * @uses apply_filters() Calls 'status_header' on status header string, HTTP 940 * HTTP code, HTTP code description, and protocol string as separate 941 * parameters. 942 * 943 * @param int $header HTTP status code 944 * @return unknown 945 */ 946 function status_header( $header ) { 947 $text = get_status_header_desc( $header ); 948 949 if ( empty( $text ) ) 950 return false; 951 952 $protocol = $_SERVER["SERVER_PROTOCOL"]; 953 if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol ) 954 $protocol = 'HTTP/1.0'; 955 $status_header = "$protocol $header $text"; 956 if ( function_exists( 'apply_filters' ) ) 957 $status_header = apply_filters( 'status_header', $status_header, $header, $text, $protocol ); 958 959 return @header( $status_header, true, $header ); 960 } 961 962 /** 963 * Gets the header information to prevent caching. 964 * 965 * The several different headers cover the different ways cache prevention is handled 966 * by different browsers 967 * 968 * @since 2.8.0 969 * 970 * @uses apply_filters() 971 * @return array The associative array of header names and field values. 972 */ 973 function wp_get_nocache_headers() { 974 $headers = array( 975 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT', 976 'Last-Modified' => gmdate( 'D, d M Y H:i:s' ) . ' GMT', 977 'Cache-Control' => 'no-cache, must-revalidate, max-age=0', 978 'Pragma' => 'no-cache', 979 ); 980 981 if ( function_exists('apply_filters') ) { 982 $headers = (array) apply_filters('nocache_headers', $headers); 983 } 984 return $headers; 985 } 986 987 /** 988 * Sets the headers to prevent caching for the different browsers. 989 * 990 * Different browsers support different nocache headers, so several headers must 991 * be sent so that all of them get the point that no caching should occur. 992 * 993 * @since 2.0.0 994 * @uses wp_get_nocache_headers() 995 */ 996 function nocache_headers() { 997 $headers = wp_get_nocache_headers(); 998 foreach( $headers as $name => $field_value ) 999 @header("{$name}: {$field_value}"); 1000 } 1001 1002 /** 1003 * Set the headers for caching for 10 days with JavaScript content type. 1004 * 1005 * @since 2.1.0 1006 */ 1007 function cache_javascript_headers() { 1008 $expiresOffset = 864000; // 10 days 1009 header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) ); 1010 header( "Vary: Accept-Encoding" ); // Handle proxies 1011 header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" ); 1012 } 1013 1014 /** 1015 * Retrieve the number of database queries during the WordPress execution. 1016 * 1017 * @since 2.0.0 1018 * 1019 * @return int Number of database queries 1020 */ 1021 function get_num_queries() { 1022 global $wpdb; 1023 return $wpdb->num_queries; 1024 } 1025 1026 /** 1027 * Whether input is yes or no. Must be 'y' to be true. 1028 * 1029 * @since 1.0.0 1030 * 1031 * @param string $yn Character string containing either 'y' or 'n' 1032 * @return bool True if yes, false on anything else 1033 */ 1034 function bool_from_yn( $yn ) { 1035 return ( strtolower( $yn ) == 'y' ); 1036 } 1037 1038 /** 1039 * Loads the feed template from the use of an action hook. 1040 * 1041 * If the feed action does not have a hook, then the function will die with a 1042 * message telling the visitor that the feed is not valid. 1043 * 1044 * It is better to only have one hook for each feed. 1045 * 1046 * @since 2.1.0 1047 * @uses $wp_query Used to tell if the use a comment feed. 1048 * @uses do_action() Calls 'do_feed_$feed' hook, if a hook exists for the feed. 1049 */ 1050 function do_feed() { 1051 global $wp_query; 1052 1053 $feed = get_query_var( 'feed' ); 1054 1055 // Remove the pad, if present. 1056 $feed = preg_replace( '/^_+/', '', $feed ); 1057 1058 if ( $feed == '' || $feed == 'feed' ) 1059 $feed = get_default_feed(); 1060 1061 $hook = 'do_feed_' . $feed; 1062 if ( !has_action($hook) ) { 1063 $message = sprintf( __( 'ERROR: %s is not a valid feed template.' ), esc_html($feed)); 1064 wp_die( $message, '', array( 'response' => 404 ) ); 1065 } 1066 1067 do_action( $hook, $wp_query->is_comment_feed ); 1068 } 1069 1070 /** 1071 * Load the RDF RSS 0.91 Feed template. 1072 * 1073 * @since 2.1.0 1074 */ 1075 function do_feed_rdf() { 1076 load_template( ABSPATH . WPINC . '/feed-rdf.php' ); 1077 } 1078 1079 /** 1080 * Load the RSS 1.0 Feed Template. 1081 * 1082 * @since 2.1.0 1083 */ 1084 function do_feed_rss() { 1085 load_template( ABSPATH . WPINC . '/feed-rss.php' ); 1086 } 1087 1088 /** 1089 * Load either the RSS2 comment feed or the RSS2 posts feed. 1090 * 1091 * @since 2.1.0 1092 * 1093 * @param bool $for_comments True for the comment feed, false for normal feed. 1094 */ 1095 function do_feed_rss2( $for_comments ) { 1096 if ( $for_comments ) 1097 load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' ); 1098 else 1099 load_template( ABSPATH . WPINC . '/feed-rss2.php' ); 1100 } 1101 1102 /** 1103 * Load either Atom comment feed or Atom posts feed. 1104 * 1105 * @since 2.1.0 1106 * 1107 * @param bool $for_comments True for the comment feed, false for normal feed. 1108 */ 1109 function do_feed_atom( $for_comments ) { 1110 if ($for_comments) 1111 load_template( ABSPATH . WPINC . '/feed-atom-comments.php'); 1112 else 1113 load_template( ABSPATH . WPINC . '/feed-atom.php' ); 1114 } 1115 1116 /** 1117 * Display the robots.txt file content. 1118 * 1119 * The echo content should be with usage of the permalinks or for creating the 1120 * robots.txt file. 1121 * 1122 * @since 2.1.0 1123 * @uses do_action() Calls 'do_robotstxt' hook for displaying robots.txt rules. 1124 */ 1125 function do_robots() { 1126 header( 'Content-Type: text/plain; charset=utf-8' ); 1127 1128 do_action( 'do_robotstxt' ); 1129 1130 $output = "User-agent: *\n"; 1131 $public = get_option( 'blog_public' ); 1132 if ( '0' == $public ) { 1133 $output .= "Disallow: /\n"; 1134 } else { 1135 $site_url = parse_url( site_url() ); 1136 $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : ''; 1137 $output .= "Disallow: $path/wp-admin/\n"; 1138 $output .= "Disallow: $path/wp-includes/\n"; 1139 } 1140 1141 echo apply_filters('robots_txt', $output, $public); 1142 } 1143 1144 /** 1145 * Test whether blog is already installed. 1146 * 1147 * The cache will be checked first. If you have a cache plugin, which saves the 1148 * cache values, then this will work. If you use the default WordPress cache, 1149 * and the database goes away, then you might have problems. 1150 * 1151 * Checks for the option siteurl for whether WordPress is installed. 1152 * 1153 * @since 2.1.0 1154 * @uses $wpdb 1155 * 1156 * @return bool Whether blog is already installed. 1157 */ 1158 function is_blog_installed() { 1159 global $wpdb; 1160 1161 // Check cache first. If options table goes away and we have true cached, oh well. 1162 if ( wp_cache_get( 'is_blog_installed' ) ) 1163 return true; 1164 1165 $suppress = $wpdb->suppress_errors(); 1166 if ( ! defined( 'WP_INSTALLING' ) ) { 1167 $alloptions = wp_load_alloptions(); 1168 } 1169 // If siteurl is not set to autoload, check it specifically 1170 if ( !isset( $alloptions['siteurl'] ) ) 1171 $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" ); 1172 else 1173 $installed = $alloptions['siteurl']; 1174 $wpdb->suppress_errors( $suppress ); 1175 1176 $installed = !empty( $installed ); 1177 wp_cache_set( 'is_blog_installed', $installed ); 1178 1179 if ( $installed ) 1180 return true; 1181 1182 // If visiting repair.php, return true and let it take over. 1183 if ( defined( 'WP_REPAIRING' ) ) 1184 return true; 1185 1186 $suppress = $wpdb->suppress_errors(); 1187 1188 // Loop over the WP tables. If none exist, then scratch install is allowed. 1189 // If one or more exist, suggest table repair since we got here because the options 1190 // table could not be accessed. 1191 $wp_tables = $wpdb->tables(); 1192 foreach ( $wp_tables as $table ) { 1193 // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install. 1194 if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table ) 1195 continue; 1196 if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table ) 1197 continue; 1198 1199 if ( ! $wpdb->get_results( "DESCRIBE $table;" ) ) 1200 continue; 1201 1202 // One or more tables exist. We are insane. 1203 1204 wp_load_translations_early(); 1205 1206 // Die with a DB error. 1207 $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' ); 1208 dead_db(); 1209 } 1210 1211 $wpdb->suppress_errors( $suppress ); 1212 1213 wp_cache_set( 'is_blog_installed', false ); 1214 1215 return false; 1216 } 1217 1218 /** 1219 * Retrieve URL with nonce added to URL query. 1220 * 1221 * @package WordPress 1222 * @subpackage Security 1223 * @since 2.0.4 1224 * 1225 * @param string $actionurl URL to add nonce action 1226 * @param string $action Optional. Nonce action name 1227 * @return string URL with nonce action added. 1228 */ 1229 function wp_nonce_url( $actionurl, $action = -1 ) { 1230 $actionurl = str_replace( '&', '&', $actionurl ); 1231 return esc_html( add_query_arg( '_wpnonce', wp_create_nonce( $action ), $actionurl ) ); 1232 } 1233 1234 /** 1235 * Retrieve or display nonce hidden field for forms. 1236 * 1237 * The nonce field is used to validate that the contents of the form came from 1238 * the location on the current site and not somewhere else. The nonce does not 1239 * offer absolute protection, but should protect against most cases. It is very 1240 * important to use nonce field in forms. 1241 * 1242 * The $action and $name are optional, but if you want to have better security, 1243 * it is strongly suggested to set those two parameters. It is easier to just 1244 * call the function without any parameters, because validation of the nonce 1245 * doesn't require any parameters, but since crackers know what the default is 1246 * it won't be difficult for them to find a way around your nonce and cause 1247 * damage. 1248 * 1249 * The input name will be whatever $name value you gave. The input value will be 1250 * the nonce creation value. 1251 * 1252 * @package WordPress 1253 * @subpackage Security 1254 * @since 2.0.4 1255 * 1256 * @param string $action Optional. Action name. 1257 * @param string $name Optional. Nonce name. 1258 * @param bool $referer Optional, default true. Whether to set the referer field for validation. 1259 * @param bool $echo Optional, default true. Whether to display or return hidden form field. 1260 * @return string Nonce field. 1261 */ 1262 function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) { 1263 $name = esc_attr( $name ); 1264 $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />'; 1265 1266 if ( $referer ) 1267 $nonce_field .= wp_referer_field( false ); 1268 1269 if ( $echo ) 1270 echo $nonce_field; 1271 1272 return $nonce_field; 1273 } 1274 1275 /** 1276 * Retrieve or display referer hidden field for forms. 1277 * 1278 * The referer link is the current Request URI from the server super global. The 1279 * input name is '_wp_http_referer', in case you wanted to check manually. 1280 * 1281 * @package WordPress 1282 * @subpackage Security 1283 * @since 2.0.4 1284 * 1285 * @param bool $echo Whether to echo or return the referer field. 1286 * @return string Referer field. 1287 */ 1288 function wp_referer_field( $echo = true ) { 1289 $ref = esc_attr( $_SERVER['REQUEST_URI'] ); 1290 $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. $ref . '" />'; 1291 1292 if ( $echo ) 1293 echo $referer_field; 1294 return $referer_field; 1295 } 1296 1297 /** 1298 * Retrieve or display original referer hidden field for forms. 1299 * 1300 * The input name is '_wp_original_http_referer' and will be either the same 1301 * value of {@link wp_referer_field()}, if that was posted already or it will 1302 * be the current page, if it doesn't exist. 1303 * 1304 * @package WordPress 1305 * @subpackage Security 1306 * @since 2.0.4 1307 * 1308 * @param bool $echo Whether to echo the original http referer 1309 * @param string $jump_back_to Optional, default is 'current'. Can be 'previous' or page you want to jump back to. 1310 * @return string Original referer field. 1311 */ 1312 function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) { 1313 $jump_back_to = ( 'previous' == $jump_back_to ) ? wp_get_referer() : $_SERVER['REQUEST_URI']; 1314 $ref = ( wp_get_original_referer() ) ? wp_get_original_referer() : $jump_back_to; 1315 $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( stripslashes( $ref ) ) . '" />'; 1316 if ( $echo ) 1317 echo $orig_referer_field; 1318 return $orig_referer_field; 1319 } 1320 1321 /** 1322 * Retrieve referer from '_wp_http_referer' or HTTP referer. If it's the same 1323 * as the current request URL, will return false. 1324 * 1325 * @package WordPress 1326 * @subpackage Security 1327 * @since 2.0.4 1328 * 1329 * @return string|bool False on failure. Referer URL on success. 1330 */ 1331 function wp_get_referer() { 1332 $ref = false; 1333 if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) 1334 $ref = $_REQUEST['_wp_http_referer']; 1335 else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) 1336 $ref = $_SERVER['HTTP_REFERER']; 1337 1338 if ( $ref && $ref !== $_SERVER['REQUEST_URI'] ) 1339 return $ref; 1340 return false; 1341 } 1342 1343 /** 1344 * Retrieve original referer that was posted, if it exists. 1345 * 1346 * @package WordPress 1347 * @subpackage Security 1348 * @since 2.0.4 1349 * 1350 * @return string|bool False if no original referer or original referer if set. 1351 */ 1352 function wp_get_original_referer() { 1353 if ( !empty( $_REQUEST['_wp_original_http_referer'] ) ) 1354 return $_REQUEST['_wp_original_http_referer']; 1355 return false; 1356 } 1357 1358 /** 1359 * Recursive directory creation based on full path. 1360 * 1361 * Will attempt to set permissions on folders. 1362 * 1363 * @since 2.0.1 1364 * 1365 * @param string $target Full path to attempt to create. 1366 * @return bool Whether the path was created. True if path already exists. 1367 */ 1368 function wp_mkdir_p( $target ) { 1369 // from php.net/mkdir user contributed notes 1370 $target = str_replace( '//', '/', $target ); 1371 1372 // safe mode fails with a trailing slash under certain PHP versions. 1373 $target = rtrim($target, '/'); // Use rtrim() instead of untrailingslashit to avoid formatting.php dependency. 1374 if ( empty($target) ) 1375 $target = '/'; 1376 1377 if ( file_exists( $target ) ) 1378 return @is_dir( $target ); 1379 1380 // Attempting to create the directory may clutter up our display. 1381 if ( @mkdir( $target ) ) { 1382 $stat = @stat( dirname( $target ) ); 1383 $dir_perms = $stat['mode'] & 0007777; // Get the permission bits. 1384 @chmod( $target, $dir_perms ); 1385 return true; 1386 } elseif ( is_dir( dirname( $target ) ) ) { 1387 return false; 1388 } 1389 1390 // If the above failed, attempt to create the parent node, then try again. 1391 if ( ( $target != '/' ) && ( wp_mkdir_p( dirname( $target ) ) ) ) 1392 return wp_mkdir_p( $target ); 1393 1394 return false; 1395 } 1396 1397 /** 1398 * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows'). 1399 * 1400 * @since 2.5.0 1401 * 1402 * @param string $path File path 1403 * @return bool True if path is absolute, false is not absolute. 1404 */ 1405 function path_is_absolute( $path ) { 1406 // this is definitive if true but fails if $path does not exist or contains a symbolic link 1407 if ( realpath($path) == $path ) 1408 return true; 1409 1410 if ( strlen($path) == 0 || $path[0] == '.' ) 1411 return false; 1412 1413 // windows allows absolute paths like this 1414 if ( preg_match('#^[a-zA-Z]:\\\\#', $path) ) 1415 return true; 1416 1417 // a path starting with / or \ is absolute; anything else is relative 1418 return ( $path[0] == '/' || $path[0] == '\\' ); 1419 } 1420 1421 /** 1422 * Join two filesystem paths together (e.g. 'give me $path relative to $base'). 1423 * 1424 * If the $path is absolute, then it the full path is returned. 1425 * 1426 * @since 2.5.0 1427 * 1428 * @param string $base 1429 * @param string $path 1430 * @return string The path with the base or absolute path. 1431 */ 1432 function path_join( $base, $path ) { 1433 if ( path_is_absolute($path) ) 1434 return $path; 1435 1436 return rtrim($base, '/') . '/' . ltrim($path, '/'); 1437 } 1438 1439 /** 1440 * Determines a writable directory for temporary files. 1441 * Function's preference is to WP_CONTENT_DIR followed by the return value of <code>sys_get_temp_dir()</code>, before finally defaulting to /tmp/ 1442 * 1443 * In the event that this function does not find a writable location, It may be overridden by the <code>WP_TEMP_DIR</code> constant in your <code>wp-config.php</code> file. 1444 * 1445 * @since 2.5.0 1446 * 1447 * @return string Writable temporary directory 1448 */ 1449 function get_temp_dir() { 1450 static $temp; 1451 if ( defined('WP_TEMP_DIR') ) 1452 return trailingslashit(WP_TEMP_DIR); 1453 1454 if ( $temp ) 1455 return trailingslashit($temp); 1456 1457 $temp = WP_CONTENT_DIR . '/'; 1458 if ( is_dir($temp) && @is_writable($temp) ) 1459 return $temp; 1460 1461 if ( function_exists('sys_get_temp_dir') ) { 1462 $temp = sys_get_temp_dir(); 1463 if ( @is_writable($temp) ) 1464 return trailingslashit($temp); 1465 } 1466 1467 $temp = ini_get('upload_tmp_dir'); 1468 if ( is_dir($temp) && @is_writable($temp) ) 1469 return trailingslashit($temp); 1470 1471 $temp = '/tmp/'; 1472 return $temp; 1473 } 1474 1475 /** 1476 * Get an array containing the current upload directory's path and url. 1477 * 1478 * Checks the 'upload_path' option, which should be from the web root folder, 1479 * and if it isn't empty it will be used. If it is empty, then the path will be 1480 * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will 1481 * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path. 1482 * 1483 * The upload URL path is set either by the 'upload_url_path' option or by using 1484 * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path. 1485 * 1486 * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in 1487 * the administration settings panel), then the time will be used. The format 1488 * will be year first and then month. 1489 * 1490 * If the path couldn't be created, then an error will be returned with the key 1491 * 'error' containing the error message. The error suggests that the parent 1492 * directory is not writable by the server. 1493 * 1494 * On success, the returned array will have many indices: 1495 * 'path' - base directory and sub directory or full path to upload directory. 1496 * 'url' - base url and sub directory or absolute URL to upload directory. 1497 * 'subdir' - sub directory if uploads use year/month folders option is on. 1498 * 'basedir' - path without subdir. 1499 * 'baseurl' - URL path without subdir. 1500 * 'error' - set to false. 1501 * 1502 * @since 2.0.0 1503 * @uses apply_filters() Calls 'upload_dir' on returned array. 1504 * 1505 * @param string $time Optional. Time formatted in 'yyyy/mm'. 1506 * @return array See above for description. 1507 */ 1508 function wp_upload_dir( $time = null ) { 1509 global $switched; 1510 $siteurl = get_option( 'siteurl' ); 1511 $upload_path = get_option( 'upload_path' ); 1512 $upload_path = trim($upload_path); 1513 $main_override = is_multisite() && defined( 'MULTISITE' ) && is_main_site(); 1514 if ( empty($upload_path) ) { 1515 $dir = WP_CONTENT_DIR . '/uploads'; 1516 } else { 1517 $dir = $upload_path; 1518 if ( 'wp-content/uploads' == $upload_path ) { 1519 $dir = WP_CONTENT_DIR . '/uploads'; 1520 } elseif ( 0 !== strpos($dir, ABSPATH) ) { 1521 // $dir is absolute, $upload_path is (maybe) relative to ABSPATH 1522 $dir = path_join( ABSPATH, $dir ); 1523 } 1524 } 1525 1526 if ( !$url = get_option( 'upload_url_path' ) ) { 1527 if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) 1528 $url = WP_CONTENT_URL . '/uploads'; 1529 else 1530 $url = trailingslashit( $siteurl ) . $upload_path; 1531 } 1532 1533 if ( defined('UPLOADS') && !$main_override && ( !isset( $switched ) || $switched === false ) ) { 1534 $dir = ABSPATH . UPLOADS; 1535 $url = trailingslashit( $siteurl ) . UPLOADS; 1536 } 1537 1538 if ( is_multisite() && !$main_override && ( !isset( $switched ) || $switched === false ) ) { 1539 if ( defined( 'BLOGUPLOADDIR' ) ) 1540 $dir = untrailingslashit(BLOGUPLOADDIR); 1541 $url = str_replace( UPLOADS, 'files', $url ); 1542 } 1543 1544 $bdir = $dir; 1545 $burl = $url; 1546 1547 $subdir = ''; 1548 if ( get_option( 'uploads_use_yearmonth_folders' ) ) { 1549 // Generate the yearly and monthly dirs 1550 if ( !$time ) 1551 $time = current_time( 'mysql' ); 1552 $y = substr( $time, 0, 4 ); 1553 $m = substr( $time, 5, 2 ); 1554 $subdir = "/$y/$m"; 1555 } 1556 1557 $dir .= $subdir; 1558 $url .= $subdir; 1559 1560 $uploads = apply_filters( 'upload_dir', array( 'path' => $dir, 'url' => $url, 'subdir' => $subdir, 'basedir' => $bdir, 'baseurl' => $burl, 'error' => false ) ); 1561 1562 // Make sure we have an uploads dir 1563 if ( ! wp_mkdir_p( $uploads['path'] ) ) { 1564 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $uploads['path'] ); 1565 return array( 'error' => $message ); 1566 } 1567 1568 return $uploads; 1569 } 1570 1571 /** 1572 * Get a filename that is sanitized and unique for the given directory. 1573 * 1574 * If the filename is not unique, then a number will be added to the filename 1575 * before the extension, and will continue adding numbers until the filename is 1576 * unique. 1577 * 1578 * The callback is passed three parameters, the first one is the directory, the 1579 * second is the filename, and the third is the extension. 1580 * 1581 * @since 2.5.0 1582 * 1583 * @param string $dir 1584 * @param string $filename 1585 * @param mixed $unique_filename_callback Callback. 1586 * @return string New filename, if given wasn't unique. 1587 */ 1588 function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) { 1589 // sanitize the file name before we begin processing 1590 $filename = sanitize_file_name($filename); 1591 1592 // separate the filename into a name and extension 1593 $info = pathinfo($filename); 1594 $ext = !empty($info['extension']) ? '.' . $info['extension'] : ''; 1595 $name = basename($filename, $ext); 1596 1597 // edge case: if file is named '.ext', treat as an empty name 1598 if ( $name === $ext ) 1599 $name = ''; 1600 1601 // Increment the file number until we have a unique file to save in $dir. Use callback if supplied. 1602 if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) { 1603 $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext ); 1604 } else { 1605 $number = ''; 1606 1607 // change '.ext' to lower case 1608 if ( $ext && strtolower($ext) != $ext ) { 1609 $ext2 = strtolower($ext); 1610 $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename ); 1611 1612 // check for both lower and upper case extension or image sub-sizes may be overwritten 1613 while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) { 1614 $new_number = $number + 1; 1615 $filename = str_replace( "$number$ext", "$new_number$ext", $filename ); 1616 $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 ); 1617 $number = $new_number; 1618 } 1619 return $filename2; 1620 } 1621 1622 while ( file_exists( $dir . "/$filename" ) ) { 1623 if ( '' == "$number$ext" ) 1624 $filename = $filename . ++$number . $ext; 1625 else 1626 $filename = str_replace( "$number$ext", ++$number . $ext, $filename ); 1627 } 1628 } 1629 1630 return $filename; 1631 } 1632 1633 /** 1634 * Create a file in the upload folder with given content. 1635 * 1636 * If there is an error, then the key 'error' will exist with the error message. 1637 * If success, then the key 'file' will have the unique file path, the 'url' key 1638 * will have the link to the new file. and the 'error' key will be set to false. 1639 * 1640 * This function will not move an uploaded file to the upload folder. It will 1641 * create a new file with the content in $bits parameter. If you move the upload 1642 * file, read the content of the uploaded file, and then you can give the 1643 * filename and content to this function, which will add it to the upload 1644 * folder. 1645 * 1646 * The permissions will be set on the new file automatically by this function. 1647 * 1648 * @since 2.0.0 1649 * 1650 * @param string $name 1651 * @param null $deprecated Never used. Set to null. 1652 * @param mixed $bits File content 1653 * @param string $time Optional. Time formatted in 'yyyy/mm'. 1654 * @return array 1655 */ 1656 function wp_upload_bits( $name, $deprecated, $bits, $time = null ) { 1657 if ( !empty( $deprecated ) ) 1658 _deprecated_argument( __FUNCTION__, '2.0' ); 1659 1660 if ( empty( $name ) ) 1661 return array( 'error' => __( 'Empty filename' ) ); 1662 1663 $wp_filetype = wp_check_filetype( $name ); 1664 if ( !$wp_filetype['ext'] ) 1665 return array( 'error' => __( 'Invalid file type' ) ); 1666 1667 $upload = wp_upload_dir( $time ); 1668 1669 if ( $upload['error'] !== false ) 1670 return $upload; 1671 1672 $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) ); 1673 if ( !is_array( $upload_bits_error ) ) { 1674 $upload[ 'error' ] = $upload_bits_error; 1675 return $upload; 1676 } 1677 1678 $filename = wp_unique_filename( $upload['path'], $name ); 1679 1680 $new_file = $upload['path'] . "/$filename"; 1681 if ( ! wp_mkdir_p( dirname( $new_file ) ) ) { 1682 $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), dirname( $new_file ) ); 1683 return array( 'error' => $message ); 1684 } 1685 1686 $ifp = @ fopen( $new_file, 'wb' ); 1687 if ( ! $ifp ) 1688 return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) ); 1689 1690 @fwrite( $ifp, $bits ); 1691 fclose( $ifp ); 1692 clearstatcache(); 1693 1694 // Set correct file permissions 1695 $stat = @ stat( dirname( $new_file ) ); 1696 $perms = $stat['mode'] & 0007777; 1697 $perms = $perms & 0000666; 1698 @ chmod( $new_file, $perms ); 1699 clearstatcache(); 1700 1701 // Compute the URL 1702 $url = $upload['url'] . "/$filename"; 1703 1704 return array( 'file' => $new_file, 'url' => $url, 'error' => false ); 1705 } 1706 1707 /** 1708 * Retrieve the file type based on the extension name. 1709 * 1710 * @package WordPress 1711 * @since 2.5.0 1712 * @uses apply_filters() Calls 'ext2type' hook on default supported types. 1713 * 1714 * @param string $ext The extension to search. 1715 * @return string|null The file type, example: audio, video, document, spreadsheet, etc. Null if not found. 1716 */ 1717 function wp_ext2type( $ext ) { 1718 $ext2type = apply_filters( 'ext2type', array( 1719 'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ), 1720 'video' => array( 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ), 1721 'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'rtf', 'wp', 'wpd' ), 1722 'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsb', 'xlsm' ), 1723 'interactive' => array( 'key', 'ppt', 'pptx', 'pptm', 'odp', 'swf' ), 1724 'text' => array( 'asc', 'csv', 'tsv', 'txt' ), 1725 'archive' => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ), 1726 'code' => array( 'css', 'htm', 'html', 'php', 'js' ), 1727 )); 1728 foreach ( $ext2type as $type => $exts ) 1729 if ( in_array( $ext, $exts ) ) 1730 return $type; 1731 } 1732 1733 /** 1734 * Retrieve the file type from the file name. 1735 * 1736 * You can optionally define the mime array, if needed. 1737 * 1738 * @since 2.0.4 1739 * 1740 * @param string $filename File name or path. 1741 * @param array $mimes Optional. Key is the file extension with value as the mime type. 1742 * @return array Values with extension first and mime type. 1743 */ 1744 function wp_check_filetype( $filename, $mimes = null ) { 1745 if ( empty($mimes) ) 1746 $mimes = get_allowed_mime_types(); 1747 $type = false; 1748 $ext = false; 1749 1750 foreach ( $mimes as $ext_preg => $mime_match ) { 1751 $ext_preg = '!\.(' . $ext_preg . ')$!i'; 1752 if ( preg_match( $ext_preg, $filename, $ext_matches ) ) { 1753 $type = $mime_match; 1754 $ext = $ext_matches[1]; 1755 break; 1756 } 1757 } 1758 1759 return compact( 'ext', 'type' ); 1760 } 1761 1762 /** 1763 * Attempt to determine the real file type of a file. 1764 * If unable to, the file name extension will be used to determine type. 1765 * 1766 * If it's determined that the extension does not match the file's real type, 1767 * then the "proper_filename" value will be set with a proper filename and extension. 1768 * 1769 * Currently this function only supports validating images known to getimagesize(). 1770 * 1771 * @since 3.0.0 1772 * 1773 * @param string $file Full path to the image. 1774 * @param string $filename The filename of the image (may differ from $file due to $file being in a tmp directory) 1775 * @param array $mimes Optional. Key is the file extension with value as the mime type. 1776 * @return array Values for the extension, MIME, and either a corrected filename or false if original $filename is valid 1777 */ 1778 function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { 1779 1780 $proper_filename = false; 1781 1782 // Do basic extension validation and MIME mapping 1783 $wp_filetype = wp_check_filetype( $filename, $mimes ); 1784 extract( $wp_filetype ); 1785 1786 // We can't do any further validation without a file to work with 1787 if ( ! file_exists( $file ) ) 1788 return compact( 'ext', 'type', 'proper_filename' ); 1789 1790 // We're able to validate images using GD 1791 if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) { 1792 1793 // Attempt to figure out what type of image it actually is 1794 $imgstats = @getimagesize( $file ); 1795 1796 // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME 1797 if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) { 1798 // This is a simplified array of MIMEs that getimagesize() can detect and their extensions 1799 // You shouldn't need to use this filter, but it's here just in case 1800 $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array( 1801 'image/jpeg' => 'jpg', 1802 'image/png' => 'png', 1803 'image/gif' => 'gif', 1804 'image/bmp' => 'bmp', 1805 'image/tiff' => 'tif', 1806 ) ); 1807 1808 // Replace whatever is after the last period in the filename with the correct extension 1809 if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) { 1810 $filename_parts = explode( '.', $filename ); 1811 array_pop( $filename_parts ); 1812 $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ]; 1813 $new_filename = implode( '.', $filename_parts ); 1814 1815 if ( $new_filename != $filename ) 1816 $proper_filename = $new_filename; // Mark that it changed 1817 1818 // Redefine the extension / MIME 1819 $wp_filetype = wp_check_filetype( $new_filename, $mimes ); 1820 extract( $wp_filetype ); 1821 } 1822 } 1823 } 1824 1825 // Let plugins try and validate other types of files 1826 // Should return an array in the style of array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename ) 1827 return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes ); 1828 } 1829 1830 /** 1831 * Retrieve list of allowed mime types and file extensions. 1832 * 1833 * @since 2.8.6 1834 * 1835 * @return array Array of mime types keyed by the file extension regex corresponding to those types. 1836 */ 1837 function get_allowed_mime_types() { 1838 static $mimes = false; 1839 1840 if ( !$mimes ) { 1841 // Accepted MIME types are set here as PCRE unless provided. 1842 $mimes = apply_filters( 'upload_mimes', array( 1843 'jpg|jpeg|jpe' => 'image/jpeg', 1844 'gif' => 'image/gif', 1845 'png' => 'image/png', 1846 'bmp' => 'image/bmp', 1847 'tif|tiff' => 'image/tiff', 1848 'ico' => 'image/x-icon', 1849 'asf|asx|wax|wmv|wmx' => 'video/asf', 1850 'avi' => 'video/avi', 1851 'divx' => 'video/divx', 1852 'flv' => 'video/x-flv', 1853 'mov|qt' => 'video/quicktime', 1854 'mpeg|mpg|mpe' => 'video/mpeg', 1855 'txt|asc|c|cc|h' => 'text/plain', 1856 'csv' => 'text/csv', 1857 'tsv' => 'text/tab-separated-values', 1858 'ics' => 'text/calendar', 1859 'rtx' => 'text/richtext', 1860 'css' => 'text/css', 1861 'htm|html' => 'text/html', 1862 'mp3|m4a|m4b' => 'audio/mpeg', 1863 'mp4|m4v' => 'video/mp4', 1864 'ra|ram' => 'audio/x-realaudio', 1865 'wav' => 'audio/wav', 1866 'ogg|oga' => 'audio/ogg', 1867 'ogv' => 'video/ogg', 1868 'mid|midi' => 'audio/midi', 1869 'wma' => 'audio/wma', 1870 'mka' => 'audio/x-matroska', 1871 'mkv' => 'video/x-matroska', 1872 'rtf' => 'application/rtf', 1873 'js' => 'application/javascript', 1874 'pdf' => 'application/pdf', 1875 'doc|docx' => 'application/msword', 1876 'pot|pps|ppt|pptx|ppam|pptm|sldm|ppsm|potm' => 'application/vnd.ms-powerpoint', 1877 'wri' => 'application/vnd.ms-write', 1878 'xla|xls|xlsx|xlt|xlw|xlam|xlsb|xlsm|xltm' => 'application/vnd.ms-excel', 1879 'mdb' => 'application/vnd.ms-access', 1880 'mpp' => 'application/vnd.ms-project', 1881 'docm|dotm' => 'application/vnd.ms-word', 1882 'pptx|sldx|ppsx|potx' => 'application/vnd.openxmlformats-officedocument.presentationml', 1883 'xlsx|xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml', 1884 'docx|dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml', 1885 'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote', 1886 'swf' => 'application/x-shockwave-flash', 1887 'class' => 'application/java', 1888 'tar' => 'application/x-tar', 1889 'zip' => 'application/zip', 1890 'gz|gzip' => 'application/x-gzip', 1891 'rar' => 'application/rar', 1892 '7z' => 'application/x-7z-compressed', 1893 'exe' => 'application/x-msdownload', 1894 // openoffice formats 1895 'odt' => 'application/vnd.oasis.opendocument.text', 1896 'odp' => 'application/vnd.oasis.opendocument.presentation', 1897 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 1898 'odg' => 'application/vnd.oasis.opendocument.graphics', 1899 'odc' => 'application/vnd.oasis.opendocument.chart', 1900 'odb' => 'application/vnd.oasis.opendocument.database', 1901 'odf' => 'application/vnd.oasis.opendocument.formula', 1902 // wordperfect formats 1903 'wp|wpd' => 'application/wordperfect', 1904 ) ); 1905 } 1906 1907 return $mimes; 1908 } 1909 1910 /** 1911 * Retrieve nonce action "Are you sure" message. 1912 * 1913 * The action is split by verb and noun. The action format is as follows: 1914 * verb-action_extra. The verb is before the first dash and has the format of 1915 * letters and no spaces and numbers. The noun is after the dash and before the 1916 * underscore, if an underscore exists. The noun is also only letters. 1917 * 1918 * The filter will be called for any action, which is not defined by WordPress. 1919 * You may use the filter for your plugin to explain nonce actions to the user, 1920 * when they get the "Are you sure?" message. The filter is in the format of 1921 * 'explain_nonce_$verb-$noun' with the $verb replaced by the found verb and the 1922 * $noun replaced by the found noun. The two parameters that are given to the 1923 * hook are the localized "Are you sure you want to do this?" message with the 1924 * extra text (the text after the underscore). 1925 * 1926 * @package WordPress 1927 * @subpackage Security 1928 * @since 2.0.4 1929 * 1930 * @param string $action Nonce action. 1931 * @return string Are you sure message. 1932 */ 1933 function wp_explain_nonce( $action ) { 1934 if ( $action !== -1 && preg_match( '/([a-z]+)-([a-z]+)(_(.+))?/', $action, $matches ) ) { 1935 $verb = $matches[1]; 1936 $noun = $matches[2]; 1937 1938 $trans = array(); 1939 $trans['update']['attachment'] = array( __( 'Your attempt to edit this attachment: “%s” has failed.' ), 'get_the_title' ); 1940 1941 $trans['add']['category'] = array( __( 'Your attempt to add this category has failed.' ), false ); 1942 $trans['delete']['category'] = array( __( 'Your attempt to delete this category: “%s” has failed.' ), 'get_cat_name' ); 1943 $trans['update']['category'] = array( __( 'Your attempt to edit this category: “%s” has failed.' ), 'get_cat_name' ); 1944 1945 $trans['delete']['comment'] = array( __( 'Your attempt to delete this comment: “%s” has failed.' ), 'use_id' ); 1946 $trans['unapprove']['comment'] = array( __( 'Your attempt to unapprove this comment: “%s” has failed.' ), 'use_id' ); 1947 $trans['approve']['comment'] = array( __( 'Your attempt to approve this comment: “%s” has failed.' ), 'use_id' ); 1948 $trans['update']['comment'] = array( __( 'Your attempt to edit this comment: “%s” has failed.' ), 'use_id' ); 1949 $trans['bulk']['comments'] = array( __( 'Your attempt to bulk modify comments has failed.' ), false ); 1950 $trans['moderate']['comments'] = array( __( 'Your attempt to moderate comments has failed.' ), false ); 1951 1952 $trans['add']['bookmark'] = array( __( 'Your attempt to add this link has failed.' ), false ); 1953 $trans['delete']['bookmark'] = array( __( 'Your attempt to delete this link: “%s” has failed.' ), 'use_id' ); 1954 $trans['update']['bookmark'] = array( __( 'Your attempt to edit this link: “%s” has failed.' ), 'use_id' ); 1955 $trans['bulk']['bookmarks'] = array( __( 'Your attempt to bulk modify links has failed.' ), false ); 1956 1957 $trans['add']['page'] = array( __( 'Your attempt to add this page has failed.' ), false ); 1958 $trans['delete']['page'] = array( __( 'Your attempt to delete this page: “%s” has failed.' ), 'get_the_title' ); 1959 $trans['update']['page'] = array( __( 'Your attempt to edit this page: “%s” has failed.' ), 'get_the_title' ); 1960 1961 $trans['edit']['plugin'] = array( __( 'Your attempt to edit this plugin file: “%s” has failed.' ), 'use_id' ); 1962 $trans['activate']['plugin'] = array( __( 'Your attempt to activate this plugin: “%s” has failed.' ), 'use_id' ); 1963 $trans['deactivate']['plugin'] = array( __( 'Your attempt to deactivate this plugin: “%s” has failed.' ), 'use_id' ); 1964 $trans['upgrade']['plugin'] = array( __( 'Your attempt to update this plugin: “%s” has failed.' ), 'use_id' ); 1965 1966 $trans['add']['post'] = array( __( 'Your attempt to add this post has failed.' ), false ); 1967 $trans['delete']['post'] = array( __( 'Your attempt to delete this post: “%s” has failed.' ), 'get_the_title' ); 1968 $trans['update']['post'] = array( __( 'Your attempt to edit this post: “%s” has failed.' ), 'get_the_title' ); 1969 1970 $trans['add']['user'] = array( __( 'Your attempt to add this user has failed.' ), false ); 1971 $trans['delete']['users'] = array( __( 'Your attempt to delete users has failed.' ), false ); 1972 $trans['bulk']['users'] = array( __( 'Your attempt to bulk modify users has failed.' ), false ); 1973 $trans['update']['user'] = array( __( 'Your attempt to edit this user: “%s” has failed.' ), 'get_the_author_meta', 'display_name' ); 1974 $trans['update']['profile'] = array( __( 'Your attempt to modify the profile for: “%s” has failed.' ), 'get_the_author_meta', 'display_name' ); 1975 1976 $trans['update']['options'] = array( __( 'Your attempt to edit your settings has failed.' ), false ); 1977 $trans['update']['permalink'] = array( __( 'Your attempt to change your permalink structure to: %s has failed.' ), 'use_id' ); 1978 $trans['edit']['file'] = array( __( 'Your attempt to edit this file: “%s” has failed.' ), 'use_id' ); 1979 $trans['edit']['theme'] = array( __( 'Your attempt to edit this theme file: “%s” has failed.' ), 'use_id' ); 1980 $trans['switch']['theme'] = array( __( 'Your attempt to switch to this theme: “%s” has failed.' ), 'use_id' ); 1981 1982 $trans['log']['out'] = array( sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'sitename' ) ), false ); 1983 1984 if ( isset( $trans[$verb][$noun] ) ) { 1985 if ( !empty( $trans[$verb][$noun][1] ) ) { 1986 $lookup = $trans[$verb][$noun][1]; 1987 if ( isset($trans[$verb][$noun][2]) ) 1988 $lookup_value = $trans[$verb][$noun][2]; 1989 $object = $matches[4]; 1990 if ( 'use_id' != $lookup ) { 1991 if ( isset( $lookup_value ) ) 1992 $object = call_user_func( $lookup, $lookup_value, $object ); 1993 else 1994 $object = call_user_func( $lookup, $object ); 1995 } 1996 return sprintf( $trans[$verb][$noun][0], esc_html($object) ); 1997 } else { 1998 return $trans[$verb][$noun][0]; 1999 } 2000 } 2001 2002 return apply_filters( 'explain_nonce_' . $verb . '-' . $noun, __( 'Are you sure you want to do this?' ), isset($matches[4]) ? $matches[4] : '' ); 2003 } else { 2004 return apply_filters( 'explain_nonce_' . $action, __( 'Are you sure you want to do this?' ) ); 2005 } 2006 } 2007 2008 /** 2009 * Display "Are You Sure" message to confirm the action being taken. 2010 * 2011 * If the action has the nonce explain message, then it will be displayed along 2012 * with the "Are you sure?" message. 2013 * 2014 * @package WordPress 2015 * @subpackage Security 2016 * @since 2.0.4 2017 * 2018 * @param string $action The nonce action. 2019 */ 2020 function wp_nonce_ays( $action ) { 2021 $title = __( 'WordPress Failure Notice' ); 2022 $html = esc_html( wp_explain_nonce( $action ) ); 2023 if ( 'log-out' == $action ) 2024 $html .= "</p><p>" . sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url() ); 2025 elseif ( wp_get_referer() ) 2026 $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>"; 2027 2028 wp_die( $html, $title, array('response' => 403) ); 2029 } 2030 2031 /** 2032 * Kill WordPress execution and display HTML message with error message. 2033 * 2034 * This function complements the die() PHP function. The difference is that 2035 * HTML will be displayed to the user. It is recommended to use this function 2036 * only, when the execution should not continue any further. It is not 2037 * recommended to call this function very often and try to handle as many errors 2038 * as possible silently. 2039 * 2040 * @since 2.0.4 2041 * 2042 * @param string $message Error message. 2043 * @param string $title Error title. 2044 * @param string|array $args Optional arguments to control behavior. 2045 */ 2046 function wp_die( $message = '', $title = '', $args = array() ) { 2047 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) 2048 $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' ); 2049 elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) 2050 $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' ); 2051 else 2052 $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' ); 2053 2054 call_user_func( $function, $message, $title, $args ); 2055 } 2056 2057 /** 2058 * Kill WordPress execution and display HTML message with error message. 2059 * 2060 * This is the default handler for wp_die if you want a custom one for your 2061 * site then you can overload using the wp_die_handler filter in wp_die 2062 * 2063 * @since 3.0.0 2064 * @access private 2065 * 2066 * @param string $message Error message. 2067 * @param string $title Error title. 2068 * @param string|array $args Optional arguments to control behavior. 2069 */ 2070 function _default_wp_die_handler( $message, $title = '', $args = array() ) { 2071 $defaults = array( 'response' => 500 ); 2072 $r = wp_parse_args($args, $defaults); 2073 2074 $have_gettext = function_exists('__'); 2075 2076 if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) { 2077 if ( empty( $title ) ) { 2078 $error_data = $message->get_error_data(); 2079 if ( is_array( $error_data ) && isset( $error_data['title'] ) ) 2080 $title = $error_data['title']; 2081 } 2082 $errors = $message->get_error_messages(); 2083 switch ( count( $errors ) ) : 2084 case 0 : 2085 $message = ''; 2086 break; 2087 case 1 : 2088 $message = "<p>{$errors[0]}</p>"; 2089 break; 2090 default : 2091 $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>"; 2092 break; 2093 endswitch; 2094 } elseif ( is_string( $message ) ) { 2095 $message = "<p>$message</p>"; 2096 } 2097 2098 if ( isset( $r['back_link'] ) && $r['back_link'] ) { 2099 $back_text = $have_gettext? __('« Back') : '« Back'; 2100 $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>"; 2101 } 2102 2103 if ( ! did_action( 'admin_head' ) ) : 2104 if ( !headers_sent() ) { 2105 status_header( $r['response'] ); 2106 nocache_headers(); 2107 header( 'Content-Type: text/html; charset=utf-8' ); 2108 } 2109 2110 if ( empty($title) ) 2111 $title = $have_gettext ? __('WordPress › Error') : 'WordPress › Error'; 2112 2113 $text_direction = 'ltr'; 2114 if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] ) 2115 $text_direction = 'rtl'; 2116 elseif ( function_exists( 'is_rtl' ) && is_rtl() ) 2117 $text_direction = 'rtl'; 2118 ?> 2119 <!DOCTYPE html> 2120 <!-- 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 2121 --> 2122 <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'"; ?>> 2123 <head> 2124 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 2125 <title><?php echo $title ?></title> 2126 <style type="text/css"> 2127 html { 2128 background: #f9f9f9; 2129 } 2130 body { 2131 background: #fff; 2132 color: #333; 2133 font-family: sans-serif; 2134 margin: 2em auto; 2135 padding: 1em 2em; 2136 -webkit-border-radius: 3px; 2137 border-radius: 3px; 2138 border: 1px solid #dfdfdf; 2139 max-width: 700px; 2140 } 2141 #error-page { 2142 margin-top: 50px; 2143 } 2144 #error-page p { 2145 font-size: 14px; 2146 line-height: 1.5; 2147 margin: 25px 0 20px; 2148 } 2149 #error-page code { 2150 font-family: Consolas, Monaco, monospace; 2151 } 2152 ul li { 2153 margin-bottom: 10px; 2154 font-size: 14px ; 2155 } 2156 a { 2157 color: #21759B; 2158 text-decoration: none; 2159 } 2160 a:hover { 2161 color: #D54E21; 2162 } 2163 2164 .button { 2165 font-family: sans-serif; 2166 text-decoration: none; 2167 font-size: 14px !important; 2168 line-height: 16px; 2169 padding: 6px 12px; 2170 cursor: pointer; 2171 border: 1px solid #bbb; 2172 color: #464646; 2173 -webkit-border-radius: 15px; 2174 border-radius: 15px; 2175 -moz-box-sizing: content-box; 2176 -webkit-box-sizing: content-box; 2177 box-sizing: content-box; 2178 background-color: #f5f5f5; 2179 background-image: -ms-linear-gradient(top, #ffffff, #f2f2f2); 2180 background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); 2181 background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); 2182 background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f2f2f2)); 2183 background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); 2184 background-image: linear-gradient(top, #ffffff, #f2f2f2); 2185 } 2186 2187 .button:hover { 2188 color: #000; 2189 border-color: #666; 2190 } 2191 2192 .button:active { 2193 background-image: -ms-linear-gradient(top, #f2f2f2, #ffffff); 2194 background-image: -moz-linear-gradient(top, #f2f2f2, #ffffff); 2195 background-image: -o-linear-gradient(top, #f2f2f2, #ffffff); 2196 background-image: -webkit-gradient(linear, left top, left bottom, from(#f2f2f2), to(#ffffff)); 2197 background-image: -webkit-linear-gradient(top, #f2f2f2, #ffffff); 2198 background-image: linear-gradient(top, #f2f2f2, #ffffff); 2199 } 2200 2201 <?php if ( 'rtl' == $text_direction ) : ?> 2202 body { font-family: Tahoma, Arial; } 2203 <?php endif; ?> 2204 </style> 2205 </head> 2206 <body id="error-page"> 2207 <?php endif; // ! did_action( 'admin_head' ) ?> 2208 <?php echo $message; ?> 2209 </body> 2210 </html> 2211 <?php 2212 die(); 2213 } 2214 2215 /** 2216 * Kill WordPress execution and display XML message with error message. 2217 * 2218 * This is the handler for wp_die when processing XMLRPC requests. 2219 * 2220 * @since 3.2.0 2221 * @access private 2222 * 2223 * @param string $message Error message. 2224 * @param string $title Error title. 2225 * @param string|array $args Optional arguments to control behavior. 2226 */ 2227 function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) { 2228 global $wp_xmlrpc_server; 2229 $defaults = array( 'response' => 500 ); 2230 2231 $r = wp_parse_args($args, $defaults); 2232 2233 if ( $wp_xmlrpc_server ) { 2234 $error = new IXR_Error( $r['response'] , $message); 2235 $wp_xmlrpc_server->output( $error->getXml() ); 2236 } 2237 die(); 2238 } 2239 2240 /** 2241 * Kill WordPress ajax execution. 2242 * 2243 * This is the handler for wp_die when processing Ajax requests. 2244 * 2245 * @since 3.4.0 2246 * @access private 2247 * 2248 * @param string $message Optional. Response to print. 2249 */ 2250 function _ajax_wp_die_handler( $message = '' ) { 2251 if ( is_scalar( $message ) ) 2252 die( (string) $message ); 2253 die( '0' ); 2254 } 2255 2256 /** 2257 * Retrieve the WordPress home page URL. 2258 * 2259 * If the constant named 'WP_HOME' exists, then it will be used and returned by 2260 * the function. This can be used to counter the redirection on your local 2261 * development environment. 2262 * 2263 * @access private 2264 * @package WordPress 2265 * @since 2.2.0 2266 * 2267 * @param string $url URL for the home location 2268 * @return string Homepage location. 2269 */ 2270 function _config_wp_home( $url = '' ) { 2271 if ( defined( 'WP_HOME' ) ) 2272 return untrailingslashit( WP_HOME ); 2273 return $url; 2274 } 2275 2276 /** 2277 * Retrieve the WordPress site URL. 2278 * 2279 * If the constant named 'WP_SITEURL' is defined, then the value in that 2280 * constant will always be returned. This can be used for debugging a site on 2281 * your localhost while not having to change the database to your URL. 2282 * 2283 * @access private 2284 * @package WordPress 2285 * @since 2.2.0 2286 * 2287 * @param string $url URL to set the WordPress site location. 2288 * @return string The WordPress Site URL 2289 */ 2290 function _config_wp_siteurl( $url = '' ) { 2291 if ( defined( 'WP_SITEURL' ) ) 2292 return untrailingslashit( WP_SITEURL ); 2293 return $url; 2294 } 2295 2296 /** 2297 * Set the localized direction for MCE plugin. 2298 * 2299 * Will only set the direction to 'rtl', if the WordPress locale has the text 2300 * direction set to 'rtl'. 2301 * 2302 * Fills in the 'directionality', 'plugins', and 'theme_advanced_button1' array 2303 * keys. These keys are then returned in the $input array. 2304 * 2305 * @access private 2306 * @package WordPress 2307 * @subpackage MCE 2308 * @since 2.1.0 2309 * 2310 * @param array $input MCE plugin array. 2311 * @return array Direction set for 'rtl', if needed by locale. 2312 */ 2313 function _mce_set_direction( $input ) { 2314 if ( is_rtl() ) { 2315 $input['directionality'] = 'rtl'; 2316 $input['plugins'] .= ',directionality'; 2317 $input['theme_advanced_buttons1'] .= ',ltr'; 2318 } 2319 2320 return $input; 2321 } 2322 2323 /** 2324 * Convert smiley code to the icon graphic file equivalent. 2325 * 2326 * You can turn off smilies, by going to the write setting screen and unchecking 2327 * the box, or by setting 'use_smilies' option to false or removing the option. 2328 * 2329 * Plugins may override the default smiley list by setting the $wpsmiliestrans 2330 * to an array, with the key the code the blogger types in and the value the 2331 * image file. 2332 * 2333 * The $wp_smiliessearch global is for the regular expression and is set each 2334 * time the function is called. 2335 * 2336 * The full list of smilies can be found in the function and won't be listed in 2337 * the description. Probably should create a Codex page for it, so that it is 2338 * available. 2339 * 2340 * @global array $wpsmiliestrans 2341 * @global array $wp_smiliessearch 2342 * @since 2.2.0 2343 */ 2344 function smilies_init() { 2345 global $wpsmiliestrans, $wp_smiliessearch; 2346 2347 // don't bother setting up smilies if they are disabled 2348 if ( !get_option( 'use_smilies' ) ) 2349 return; 2350 2351 if ( !isset( $wpsmiliestrans ) ) { 2352 $wpsmiliestrans = array( 2353 ':mrgreen:' => 'icon_mrgreen.gif', 2354 ':neutral:' => 'icon_neutral.gif', 2355 ':twisted:' => 'icon_twisted.gif', 2356 ':arrow:' => 'icon_arrow.gif', 2357 ':shock:' => 'icon_eek.gif', 2358 ':smile:' => 'icon_smile.gif', 2359 ':???:' => 'icon_confused.gif', 2360 ':cool:' => 'icon_cool.gif', 2361 ':evil:' => 'icon_evil.gif', 2362 ':grin:' => 'icon_biggrin.gif', 2363 ':idea:' => 'icon_idea.gif', 2364 ':oops:' => 'icon_redface.gif', 2365 ':razz:' => 'icon_razz.gif', 2366 ':roll:' => 'icon_rolleyes.gif', 2367 ':wink:' => 'icon_wink.gif', 2368 ':cry:' => 'icon_cry.gif', 2369 ':eek:' => 'icon_surprised.gif', 2370 ':lol:' => 'icon_lol.gif', 2371 ':mad:' => 'icon_mad.gif', 2372 ':sad:' => 'icon_sad.gif', 2373 '8-)' => 'icon_cool.gif', 2374 '8-O' => 'icon_eek.gif', 2375 ':-(' => 'icon_sad.gif', 2376 ':-)' => 'icon_smile.gif', 2377 ':-?' => 'icon_confused.gif', 2378 ':-D' => 'icon_biggrin.gif', 2379 ':-P' => 'icon_razz.gif', 2380 ':-o' => 'icon_surprised.gif', 2381 ':-x' => 'icon_mad.gif', 2382 ':-|' => 'icon_neutral.gif', 2383 ';-)' => 'icon_wink.gif', 2384 // This one transformation breaks regular text with frequency. 2385 // '8)' => 'icon_cool.gif', 2386 '8O' => 'icon_eek.gif', 2387 ':(' => 'icon_sad.gif', 2388 ':)' => 'icon_smile.gif', 2389 ':?' => 'icon_confused.gif', 2390 ':D' => 'icon_biggrin.gif', 2391 ':P' => 'icon_razz.gif', 2392 ':o' => 'icon_surprised.gif', 2393 ':x' => 'icon_mad.gif', 2394 ':|' => 'icon_neutral.gif', 2395 ';)' => 'icon_wink.gif', 2396 ':!:' => 'icon_exclaim.gif', 2397 ':?:' => 'icon_question.gif', 2398 ); 2399 } 2400 2401 if (count($wpsmiliestrans) == 0) { 2402 return; 2403 } 2404 2405 /* 2406 * NOTE: we sort the smilies in reverse key order. This is to make sure 2407 * we match the longest possible smilie (:???: vs :?) as the regular 2408 * expression used below is first-match 2409 */ 2410 krsort($wpsmiliestrans); 2411 2412 $wp_smiliessearch = '/(?:\s|^)'; 2413 2414 $subchar = ''; 2415 foreach ( (array) $wpsmiliestrans as $smiley => $img ) { 2416 $firstchar = substr($smiley, 0, 1); 2417 $rest = substr($smiley, 1); 2418 2419 // new subpattern? 2420 if ($firstchar != $subchar) { 2421 if ($subchar != '') { 2422 $wp_smiliessearch .= ')|(?:\s|^)'; 2423 } 2424 $subchar = $firstchar; 2425 $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:'; 2426 } else { 2427 $wp_smiliessearch .= '|'; 2428 } 2429 $wp_smiliessearch .= preg_quote($rest, '/'); 2430 } 2431 2432 $wp_smiliessearch .= ')(?:\s|$)/m'; 2433 } 2434 2435 /** 2436 * Merge user defined arguments into defaults array. 2437 * 2438 * This function is used throughout WordPress to allow for both string or array 2439 * to be merged into another array. 2440 * 2441 * @since 2.2.0 2442 * 2443 * @param string|array $args Value to merge with $defaults 2444 * @param array $defaults Array that serves as the defaults. 2445 * @return array Merged user defined values with defaults. 2446 */ 2447 function wp_parse_args( $args, $defaults = '' ) { 2448 if ( is_object( $args ) ) 2449 $r = get_object_vars( $args ); 2450 elseif ( is_array( $args ) ) 2451 $r =& $args; 2452 else 2453 wp_parse_str( $args, $r ); 2454 2455 if ( is_array( $defaults ) ) 2456 return array_merge( $defaults, $r ); 2457 return $r; 2458 } 2459 2460 /** 2461 * Clean up an array, comma- or space-separated list of IDs. 2462 * 2463 * @since 3.0.0 2464 * 2465 * @param array|string $list 2466 * @return array Sanitized array of IDs 2467 */ 2468 function wp_parse_id_list( $list ) { 2469 if ( !is_array($list) ) 2470 $list = preg_split('/[\s,]+/', $list); 2471 2472 return array_unique(array_map('absint', $list)); 2473 } 2474 2475 /** 2476 * Extract a slice of an array, given a list of keys. 2477 * 2478 * @since 3.1.0 2479 * 2480 * @param array $array The original array 2481 * @param array $keys The list of keys 2482 * @return array The array slice 2483 */ 2484 function wp_array_slice_assoc( $array, $keys ) { 2485 $slice = array(); 2486 foreach ( $keys as $key ) 2487 if ( isset( $array[ $key ] ) ) 2488 $slice[ $key ] = $array[ $key ]; 2489 2490 return $slice; 2491 } 2492 2493 /** 2494 * Filters a list of objects, based on a set of key => value arguments. 2495 * 2496 * @since 3.0.0 2497 * 2498 * @param array $list An array of objects to filter 2499 * @param array $args An array of key => value arguments to match against each object 2500 * @param string $operator The logical operation to perform. 'or' means only one element 2501 * from the array needs to match; 'and' means all elements must match. The default is 'and'. 2502 * @param bool|string $field A field from the object to place instead of the entire object 2503 * @return array A list of objects or object fields 2504 */ 2505 function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) { 2506 if ( ! is_array( $list ) ) 2507 return array(); 2508 2509 $list = wp_list_filter( $list,