[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ -> functions.php (source)

   1  <?php
   2  /**
   3   * Main WordPress API
   4   *
   5   * @package WordPress
   6   */
   7  
   8  require ( ABSPATH . WPINC . '/option.php' );
   9  
  10  /**
  11   * Convert given date string into a different format.
  12   *
  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.
  15   *
  16   * If $translate is true then the given date and format string will
  17   * be passed to date_i18n() for translation.
  18   *
  19   * @since 0.71
  20   *
  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.
  25   */
  26  function mysql2date( $format, $date, $translate = true ) {
  27      if ( empty( $date ) ) {
  28          return false;
  29      }
  30  
  31      if ( 'G' == $format ) {
  32          return strtotime( $date . ' +0000' );
  33      }
  34  
  35      $i = strtotime( $date );
  36  
  37      if ( 'U' == $format ) {
  38          return $i;
  39      }
  40  
  41      if ( $translate ) {
  42          return date_i18n( $format, $i );
  43      } else {
  44          return date( $format, $i );
  45      }
  46  }
  47  
  48  /**
  49   * Retrieve the current time based on specified type.
  50   *
  51   * The 'mysql' type will return the time in the format for MySQL DATETIME field.
  52   * The 'timestamp' type will return the current timestamp.
  53   * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
  54   *
  55   * If $gmt is set to either '1' or 'true', then both types will use GMT time.
  56   * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
  57   *
  58   * @since 1.0.0
  59   *
  60   * @param string   $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date
  61   *                       format string (e.g. 'Y-m-d').
  62   * @param int|bool $gmt  Optional. Whether to use GMT timezone. Default false.
  63   * @return int|string Integer if $type is 'timestamp', string otherwise.
  64   */
  65  function current_time( $type, $gmt = 0 ) {
  66      switch ( $type ) {
  67          case 'mysql':
  68              return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
  69          case 'timestamp':
  70              return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  71          default:
  72              return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
  73      }
  74  }
  75  
  76  /**
  77   * Retrieve the date in localized format, based on timestamp.
  78   *
  79   * If the locale specifies the locale month and weekday, then the locale will
  80   * take over the format for the date. If it isn't, then the date format string
  81   * will be used instead.
  82   *
  83   * @since 0.71
  84   *
  85   * @global WP_Locale $wp_locale
  86   *
  87   * @param string   $dateformatstring Format to display the date.
  88   * @param bool|int $unixtimestamp    Optional. Unix timestamp. Default false.
  89   * @param bool     $gmt              Optional. Whether to use GMT timezone. Default false.
  90   *
  91   * @return string The date, translated if locale specifies it.
  92   */
  93  function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
  94      global $wp_locale;
  95      $i = $unixtimestamp;
  96  
  97      if ( false === $i ) {
  98          $i = current_time( 'timestamp', $gmt );
  99      }
 100  
 101      /*
 102       * Store original value for language with untypical grammars.
 103       * See https://core.trac.wordpress.org/ticket/9396
 104       */
 105      $req_format = $dateformatstring;
 106  
 107      if ( ( ! empty( $wp_locale->month ) ) && ( ! empty( $wp_locale->weekday ) ) ) {
 108          $datemonth            = $wp_locale->get_month( date( 'm', $i ) );
 109          $datemonth_abbrev     = $wp_locale->get_month_abbrev( $datemonth );
 110          $dateweekday          = $wp_locale->get_weekday( date( 'w', $i ) );
 111          $dateweekday_abbrev   = $wp_locale->get_weekday_abbrev( $dateweekday );
 112          $datemeridiem         = $wp_locale->get_meridiem( date( 'a', $i ) );
 113          $datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) );
 114          $dateformatstring     = ' ' . $dateformatstring;
 115          $dateformatstring     = preg_replace( '/([^\\\])D/', "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
 116          $dateformatstring     = preg_replace( '/([^\\\])F/', "\\1" . backslashit( $datemonth ), $dateformatstring );
 117          $dateformatstring     = preg_replace( '/([^\\\])l/', "\\1" . backslashit( $dateweekday ), $dateformatstring );
 118          $dateformatstring     = preg_replace( '/([^\\\])M/', "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
 119          $dateformatstring     = preg_replace( '/([^\\\])a/', "\\1" . backslashit( $datemeridiem ), $dateformatstring );
 120          $dateformatstring     = preg_replace( '/([^\\\])A/', "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
 121  
 122          $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 );
 123      }
 124      $timezone_formats    = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
 125      $timezone_formats_re = implode( '|', $timezone_formats );
 126      if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
 127          $timezone_string = get_option( 'timezone_string' );
 128          if ( $timezone_string ) {
 129              $timezone_object = timezone_open( $timezone_string );
 130              $date_object     = date_create( null, $timezone_object );
 131              foreach ( $timezone_formats as $timezone_format ) {
 132                  if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
 133                      $formatted        = date_format( $date_object, $timezone_format );
 134                      $dateformatstring = ' ' . $dateformatstring;
 135                      $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
 136                      $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) - 1 );
 137                  }
 138              }
 139          }
 140      }
 141      $j = @date( $dateformatstring, $i );
 142  
 143      /**
 144       * Filters the date formatted based on the locale.
 145       *
 146       * @since 2.8.0
 147       *
 148       * @param string $j          Formatted date string.
 149       * @param string $req_format Format to display the date.
 150       * @param int    $i          Unix timestamp.
 151       * @param bool   $gmt        Whether to convert to GMT for time. Default false.
 152       */
 153      $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
 154      return $j;
 155  }
 156  
 157  /**
 158   * Determines if the date should be declined.
 159   *
 160   * If the locale specifies that month names require a genitive case in certain
 161   * formats (like 'j F Y'), the month name will be replaced with a correct form.
 162   *
 163   * @since 4.4.0
 164   *
 165   * @global WP_Locale $wp_locale
 166   *
 167   * @param string $date Formatted date string.
 168   * @return string The date, declined if locale specifies it.
 169   */
 170  function wp_maybe_decline_date( $date ) {
 171      global $wp_locale;
 172  
 173      // i18n functions are not available in SHORTINIT mode
 174      if ( ! function_exists( '_x' ) ) {
 175          return $date;
 176      }
 177  
 178      /* translators: If months in your language require a genitive case,
 179       * translate this to 'on'. Do not translate into your own language.
 180       */
 181      if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
 182          // Match a format like 'j F Y' or 'j. F'
 183          if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
 184              $months          = $wp_locale->month;
 185              $months_genitive = $wp_locale->month_genitive;
 186  
 187              foreach ( $months as $key => $month ) {
 188                  $months[ $key ] = '# ' . $month . '( |$)#u';
 189              }
 190  
 191              foreach ( $months_genitive as $key => $month ) {
 192                  $months_genitive[ $key ] = ' ' . $month . '$1';
 193              }
 194  
 195              $date = preg_replace( $months, $months_genitive, $date );
 196          }
 197      }
 198  
 199      // Used for locale-specific rules
 200      $locale = get_locale();
 201  
 202      if ( 'ca' === $locale ) {
 203          // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
 204          $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
 205      }
 206  
 207      return $date;
 208  }
 209  
 210  /**
 211   * Convert float number to format based on the locale.
 212   *
 213   * @since 2.3.0
 214   *
 215   * @global WP_Locale $wp_locale
 216   *
 217   * @param float $number   The number to convert based on locale.
 218   * @param int   $decimals Optional. Precision of the number of decimal places. Default 0.
 219   * @return string Converted number in string format.
 220   */
 221  function number_format_i18n( $number, $decimals = 0 ) {
 222      global $wp_locale;
 223  
 224      if ( isset( $wp_locale ) ) {
 225          $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
 226      } else {
 227          $formatted = number_format( $number, absint( $decimals ) );
 228      }
 229  
 230      /**
 231       * Filters the number formatted based on the locale.
 232       *
 233       * @since 2.8.0
 234       * @since 4.9.0 The `$number` and `$decimals` parameters were added.
 235       *
 236       * @param string $formatted Converted number in string format.
 237       * @param float  $number    The number to convert based on locale.
 238       * @param int    $decimals  Precision of the number of decimal places.
 239       */
 240      return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
 241  }
 242  
 243  /**
 244   * Convert number of bytes largest unit bytes will fit into.
 245   *
 246   * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
 247   * number of bytes to human readable number by taking the number of that unit
 248   * that the bytes will go into it. Supports TB value.
 249   *
 250   * Please note that integers in PHP are limited to 32 bits, unless they are on
 251   * 64 bit architecture, then they have 64 bit size. If you need to place the
 252   * larger size then what PHP integer type will hold, then use a string. It will
 253   * be converted to a double, which should always have 64 bit length.
 254   *
 255   * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
 256   *
 257   * @since 2.3.0
 258   *
 259   * @param int|string $bytes    Number of bytes. Note max integer size for integers.
 260   * @param int        $decimals Optional. Precision of number of decimal places. Default 0.
 261   * @return string|false False on failure. Number string on success.
 262   */
 263  function size_format( $bytes, $decimals = 0 ) {
 264      $quant = array(
 265          'TB' => TB_IN_BYTES,
 266          'GB' => GB_IN_BYTES,
 267          'MB' => MB_IN_BYTES,
 268          'KB' => KB_IN_BYTES,
 269          'B'  => 1,
 270      );
 271  
 272      if ( 0 === $bytes ) {
 273          return number_format_i18n( 0, $decimals ) . ' B';
 274      }
 275  
 276      foreach ( $quant as $unit => $mag ) {
 277          if ( doubleval( $bytes ) >= $mag ) {
 278              return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
 279          }
 280      }
 281  
 282      return false;
 283  }
 284  
 285  /**
 286   * Get the week start and end from the datetime or date string from MySQL.
 287   *
 288   * @since 0.71
 289   *
 290   * @param string     $mysqlstring   Date or datetime field type from MySQL.
 291   * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
 292   * @return array Keys are 'start' and 'end'.
 293   */
 294  function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
 295      // MySQL string year.
 296      $my = substr( $mysqlstring, 0, 4 );
 297  
 298      // MySQL string month.
 299      $mm = substr( $mysqlstring, 8, 2 );
 300  
 301      // MySQL string day.
 302      $md = substr( $mysqlstring, 5, 2 );
 303  
 304      // The timestamp for MySQL string day.
 305      $day = mktime( 0, 0, 0, $md, $mm, $my );
 306  
 307      // The day of the week from the timestamp.
 308      $weekday = date( 'w', $day );
 309  
 310      if ( ! is_numeric( $start_of_week ) ) {
 311          $start_of_week = get_option( 'start_of_week' );
 312      }
 313  
 314      if ( $weekday < $start_of_week ) {
 315          $weekday += 7;
 316      }
 317  
 318      // The most recent week start day on or before $day.
 319      $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
 320  
 321      // $start + 1 week - 1 second.
 322      $end = $start + WEEK_IN_SECONDS - 1;
 323      return compact( 'start', 'end' );
 324  }
 325  
 326  /**
 327   * Unserialize value only if it was serialized.
 328   *
 329   * @since 2.0.0
 330   *
 331   * @param string $original Maybe unserialized original, if is needed.
 332   * @return mixed Unserialized data can be any type.
 333   */
 334  function maybe_unserialize( $original ) {
 335      if ( is_serialized( $original ) ) { // don't attempt to unserialize data that wasn't serialized going in
 336          return @unserialize( $original );
 337      }
 338      return $original;
 339  }
 340  
 341  /**
 342   * Check value to find if it was serialized.
 343   *
 344   * If $data is not an string, then returned value will always be false.
 345   * Serialized data is always a string.
 346   *
 347   * @since 2.0.5
 348   *
 349   * @param string $data   Value to check to see if was serialized.
 350   * @param bool   $strict Optional. Whether to be strict about the end of the string. Default true.
 351   * @return bool False if not serialized and true if it was.
 352   */
 353  function is_serialized( $data, $strict = true ) {
 354      // if it isn't a string, it isn't serialized.
 355      if ( ! is_string( $data ) ) {
 356          return false;
 357      }
 358      $data = trim( $data );
 359      if ( 'N;' == $data ) {
 360          return true;
 361      }
 362      if ( strlen( $data ) < 4 ) {
 363          return false;
 364      }
 365      if ( ':' !== $data[1] ) {
 366          return false;
 367      }
 368      if ( $strict ) {
 369          $lastc = substr( $data, -1 );
 370          if ( ';' !== $lastc && '}' !== $lastc ) {
 371              return false;
 372          }
 373      } else {
 374          $semicolon = strpos( $data, ';' );
 375          $brace     = strpos( $data, '}' );
 376          // Either ; or } must exist.
 377          if ( false === $semicolon && false === $brace ) {
 378              return false;
 379          }
 380          // But neither must be in the first X characters.
 381          if ( false !== $semicolon && $semicolon < 3 ) {
 382              return false;
 383          }
 384          if ( false !== $brace && $brace < 4 ) {
 385              return false;
 386          }
 387      }
 388      $token = $data[0];
 389      switch ( $token ) {
 390          case 's':
 391              if ( $strict ) {
 392                  if ( '"' !== substr( $data, -2, 1 ) ) {
 393                      return false;
 394                  }
 395              } elseif ( false === strpos( $data, '"' ) ) {
 396                  return false;
 397              }
 398              // or else fall through
 399          case 'a':
 400          case 'O':
 401              return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
 402          case 'b':
 403          case 'i':
 404          case 'd':
 405              $end = $strict ? '$' : '';
 406              return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
 407      }
 408      return false;
 409  }
 410  
 411  /**
 412   * Check whether serialized data is of string type.
 413   *
 414   * @since 2.0.5
 415   *
 416   * @param string $data Serialized data.
 417   * @return bool False if not a serialized string, true if it is.
 418   */
 419  function is_serialized_string( $data ) {
 420      // if it isn't a string, it isn't a serialized string.
 421      if ( ! is_string( $data ) ) {
 422          return false;
 423      }
 424      $data = trim( $data );
 425      if ( strlen( $data ) < 4 ) {
 426          return false;
 427      } elseif ( ':' !== $data[1] ) {
 428          return false;
 429      } elseif ( ';' !== substr( $data, -1 ) ) {
 430          return false;
 431      } elseif ( $data[0] !== 's' ) {
 432          return false;
 433      } elseif ( '"' !== substr( $data, -2, 1 ) ) {
 434          return false;
 435      } else {
 436          return true;
 437      }
 438  }
 439  
 440  /**
 441   * Serialize data, if needed.
 442   *
 443   * @since 2.0.5
 444   *
 445   * @param string|array|object $data Data that might be serialized.
 446   * @return mixed A scalar data
 447   */
 448  function maybe_serialize( $data ) {
 449      if ( is_array( $data ) || is_object( $data ) ) {
 450          return serialize( $data );
 451      }
 452  
 453      // Double serialization is required for backward compatibility.
 454      // See https://core.trac.wordpress.org/ticket/12930
 455      // Also the world will end. See WP 3.6.1.
 456      if ( is_serialized( $data, false ) ) {
 457          return serialize( $data );
 458      }
 459  
 460      return $data;
 461  }
 462  
 463  /**
 464   * Retrieve post title from XMLRPC XML.
 465   *
 466   * If the title element is not part of the XML, then the default post title from
 467   * the $post_default_title will be used instead.
 468   *
 469   * @since 0.71
 470   *
 471   * @global string $post_default_title Default XML-RPC post title.
 472   *
 473   * @param string $content XMLRPC XML Request content
 474   * @return string Post title
 475   */
 476  function xmlrpc_getposttitle( $content ) {
 477      global $post_default_title;
 478      if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
 479          $post_title = $matchtitle[1];
 480      } else {
 481          $post_title = $post_default_title;
 482      }
 483      return $post_title;
 484  }
 485  
 486  /**
 487   * Retrieve the post category or categories from XMLRPC XML.
 488   *
 489   * If the category element is not found, then the default post category will be
 490   * used. The return type then would be what $post_default_category. If the
 491   * category is found, then it will always be an array.
 492   *
 493   * @since 0.71
 494   *
 495   * @global string $post_default_category Default XML-RPC post category.
 496   *
 497   * @param string $content XMLRPC XML Request content
 498   * @return string|array List of categories or category name.
 499   */
 500  function xmlrpc_getpostcategory( $content ) {
 501      global $post_default_category;
 502      if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
 503          $post_category = trim( $matchcat[1], ',' );
 504          $post_category = explode( ',', $post_category );
 505      } else {
 506          $post_category = $post_default_category;
 507      }
 508      return $post_category;
 509  }
 510  
 511  /**
 512   * XMLRPC XML content without title and category elements.
 513   *
 514   * @since 0.71
 515   *
 516   * @param string $content XML-RPC XML Request content.
 517   * @return string XMLRPC XML Request content without title and category elements.
 518   */
 519  function xmlrpc_removepostdata( $content ) {
 520      $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
 521      $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
 522      $content = trim( $content );
 523      return $content;
 524  }
 525  
 526  /**
 527   * Use RegEx to extract URLs from arbitrary content.
 528   *
 529   * @since 3.7.0
 530   *
 531   * @param string $content Content to extract URLs from.
 532   * @return array URLs found in passed string.
 533   */
 534  function wp_extract_urls( $content ) {
 535      preg_match_all(
 536          "#([\"']?)("
 537              . '(?:([\w-]+:)?//?)'
 538              . '[^\s()<>]+'
 539              . '[.]'
 540              . '(?:'
 541                  . '\([\w\d]+\)|'
 542                  . '(?:'
 543                      . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
 544                      . '(?:[:]\d+)?/?'
 545                  . ')+'
 546              . ')'
 547          . ")\\1#",
 548          $content,
 549          $post_links
 550      );
 551  
 552      $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
 553  
 554      return array_values( $post_links );
 555  }
 556  
 557  /**
 558   * Check content for video and audio links to add as enclosures.
 559   *
 560   * Will not add enclosures that have already been added and will
 561   * remove enclosures that are no longer in the post. This is called as
 562   * pingbacks and trackbacks.
 563   *
 564   * @since 1.5.0
 565   *
 566   * @global wpdb $wpdb WordPress database abstraction object.
 567   *
 568   * @param string $content Post Content.
 569   * @param int    $post_ID Post ID.
 570   */
 571  function do_enclose( $content, $post_ID ) {
 572      global $wpdb;
 573  
 574      //TODO: Tidy this ghetto code up and make the debug code optional
 575      include_once ( ABSPATH . WPINC . '/class-IXR.php' );
 576  
 577      $post_links = array();
 578  
 579      $pung = get_enclosed( $post_ID );
 580  
 581      $post_links_temp = wp_extract_urls( $content );
 582  
 583      foreach ( $pung as $link_test ) {
 584          if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
 585              $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 ) . '%' ) );
 586              foreach ( $mids as $mid ) {
 587                  delete_metadata_by_mid( 'post', $mid );
 588              }
 589          }
 590      }
 591  
 592      foreach ( (array) $post_links_temp as $link_test ) {
 593          if ( ! in_array( $link_test, $pung ) ) { // If we haven't pung it already
 594              $test = @parse_url( $link_test );
 595              if ( false === $test ) {
 596                  continue;
 597              }
 598              if ( isset( $test['query'] ) ) {
 599                  $post_links[] = $link_test;
 600              } elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) ) {
 601                  $post_links[] = $link_test;
 602              }
 603          }
 604      }
 605  
 606      /**
 607       * Filters the list of enclosure links before querying the database.
 608       *
 609       * Allows for the addition and/or removal of potential enclosures to save
 610       * to postmeta before checking the database for existing enclosures.
 611       *
 612       * @since 4.4.0
 613       *
 614       * @param array $post_links An array of enclosure links.
 615       * @param int   $post_ID    Post ID.
 616       */
 617      $post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
 618  
 619      foreach ( (array) $post_links as $url ) {
 620          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 ) . '%' ) ) ) {
 621  
 622              if ( $headers = wp_get_http_headers( $url ) ) {
 623                  $len           = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
 624                  $type          = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
 625                  $allowed_types = array( 'video', 'audio' );
 626  
 627                  // Check to see if we can figure out the mime type from
 628                  // the extension
 629                  $url_parts = @parse_url( $url );
 630                  if ( false !== $url_parts ) {
 631                      $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
 632                      if ( ! empty( $extension ) ) {
 633                          foreach ( wp_get_mime_types() as $exts => $mime ) {
 634                              if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
 635                                  $type = $mime;
 636                                  break;
 637                              }
 638                          }
 639                      }
 640                  }
 641  
 642                  if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) {
 643                      add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
 644                  }
 645              }
 646          }
 647      }
 648  }
 649  
 650  /**
 651   * Retrieve HTTP Headers from URL.
 652   *
 653   * @since 1.5.1
 654   *
 655   * @param string $url        URL to retrieve HTTP headers from.
 656   * @param bool   $deprecated Not Used.
 657   * @return bool|string False on failure, headers on success.
 658   */
 659  function wp_get_http_headers( $url, $deprecated = false ) {
 660      if ( ! empty( $deprecated ) ) {
 661          _deprecated_argument( __FUNCTION__, '2.7.0' );
 662      }
 663  
 664      $response = wp_safe_remote_head( $url );
 665  
 666      if ( is_wp_error( $response ) ) {
 667          return false;
 668      }
 669  
 670      return wp_remote_retrieve_headers( $response );
 671  }
 672  
 673  /**
 674   * Determines whether the publish date of the current post in the loop is different
 675   * from the publish date of the previous post in the loop.
 676   *
 677   * For more information on this and similar theme functions, check out
 678   * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
 679   * Conditional Tags} article in the Theme Developer Handbook.
 680   *
 681   * @since 0.71
 682   *
 683   * @global string $currentday  The day of the current post in the loop.
 684   * @global string $previousday The day of the previous post in the loop.
 685   *
 686   * @return int 1 when new day, 0 if not a new day.
 687   */
 688  function is_new_day() {
 689      global $currentday, $previousday;
 690      if ( $currentday != $previousday ) {
 691          return 1;
 692      } else {
 693          return 0;
 694      }
 695  }
 696  
 697  /**
 698   * Build URL query based on an associative and, or indexed array.
 699   *
 700   * This is a convenient function for easily building url queries. It sets the
 701   * separator to '&' and uses _http_build_query() function.
 702   *
 703   * @since 2.3.0
 704   *
 705   * @see _http_build_query() Used to build the query
 706   * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
 707   *       http_build_query() does.
 708   *
 709   * @param array $data URL-encode key/value pairs.
 710   * @return string URL-encoded string.
 711   */
 712  function build_query( $data ) {
 713      return _http_build_query( $data, null, '&', '', false );
 714  }
 715  
 716  /**
 717   * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
 718   *
 719   * @since 3.2.0
 720   * @access private
 721   *
 722   * @see https://secure.php.net/manual/en/function.http-build-query.php
 723   *
 724   * @param array|object  $data       An array or object of data. Converted to array.
 725   * @param string        $prefix     Optional. Numeric index. If set, start parameter numbering with it.
 726   *                                  Default null.
 727   * @param string        $sep        Optional. Argument separator; defaults to 'arg_separator.output'.
 728   *                                  Default null.
 729   * @param string        $key        Optional. Used to prefix key name. Default empty.
 730   * @param bool          $urlencode  Optional. Whether to use urlencode() in the result. Default true.
 731   *
 732   * @return string The query string.
 733   */
 734  function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
 735      $ret = array();
 736  
 737      foreach ( (array) $data as $k => $v ) {
 738          if ( $urlencode ) {
 739              $k = urlencode( $k );
 740          }
 741          if ( is_int( $k ) && $prefix != null ) {
 742              $k = $prefix . $k;
 743          }
 744          if ( ! empty( $key ) ) {
 745              $k = $key . '%5B' . $k . '%5D';
 746          }
 747          if ( $v === null ) {
 748              continue;
 749          } elseif ( $v === false ) {
 750              $v = '0';
 751          }
 752  
 753          if ( is_array( $v ) || is_object( $v ) ) {
 754              array_push( $ret, _http_build_query( $v, '', $sep, $k, $urlencode ) );
 755          } elseif ( $urlencode ) {
 756              array_push( $ret, $k . '=' . urlencode( $v ) );
 757          } else {
 758              array_push( $ret, $k . '=' . $v );
 759          }
 760      }
 761  
 762      if ( null === $sep ) {
 763          $sep = ini_get( 'arg_separator.output' );
 764      }
 765  
 766      return implode( $sep, $ret );
 767  }
 768  
 769  /**
 770   * Retrieves a modified URL query string.
 771   *
 772   * You can rebuild the URL and append query variables to the URL query by using this function.
 773   * There are two ways to use this function; either a single key and value, or an associative array.
 774   *
 775   * Using a single key and value:
 776   *
 777   *     add_query_arg( 'key', 'value', 'http://example.com' );
 778   *
 779   * Using an associative array:
 780   *
 781   *     add_query_arg( array(
 782   *         'key1' => 'value1',
 783   *         'key2' => 'value2',
 784   *     ), 'http://example.com' );
 785   *
 786   * Omitting the URL from either use results in the current URL being used
 787   * (the value of `$_SERVER['REQUEST_URI']`).
 788   *
 789   * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
 790   *
 791   * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
 792   *
 793   * Important: The return value of add_query_arg() is not escaped by default. Output should be
 794   * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
 795   * (XSS) attacks.
 796   *
 797   * @since 1.5.0
 798   *
 799   * @param string|array $key   Either a query variable key, or an associative array of query variables.
 800   * @param string       $value Optional. Either a query variable value, or a URL to act upon.
 801   * @param string       $url   Optional. A URL to act upon.
 802   * @return string New URL query string (unescaped).
 803   */
 804  function add_query_arg() {
 805      $args = func_get_args();
 806      if ( is_array( $args[0] ) ) {
 807          if ( count( $args ) < 2 || false === $args[1] ) {
 808              $uri = $_SERVER['REQUEST_URI'];
 809          } else {
 810              $uri = $args[1];
 811          }
 812      } else {
 813          if ( count( $args ) < 3 || false === $args[2] ) {
 814              $uri = $_SERVER['REQUEST_URI'];
 815          } else {
 816              $uri = $args[2];
 817          }
 818      }
 819  
 820      if ( $frag = strstr( $uri, '#' ) ) {
 821          $uri = substr( $uri, 0, -strlen( $frag ) );
 822      } else {
 823          $frag = '';
 824      }
 825  
 826      if ( 0 === stripos( $uri, 'http://' ) ) {
 827          $protocol = 'http://';
 828          $uri      = substr( $uri, 7 );
 829      } elseif ( 0 === stripos( $uri, 'https://' ) ) {
 830          $protocol = 'https://';
 831          $uri      = substr( $uri, 8 );
 832      } else {
 833          $protocol = '';
 834      }
 835  
 836      if ( strpos( $uri, '?' ) !== false ) {
 837          list( $base, $query ) = explode( '?', $uri, 2 );
 838          $base                .= '?';
 839      } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
 840          $base  = $uri . '?';
 841          $query = '';
 842      } else {
 843          $base  = '';
 844          $query = $uri;
 845      }
 846  
 847      wp_parse_str( $query, $qs );
 848      $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
 849      if ( is_array( $args[0] ) ) {
 850          foreach ( $args[0] as $k => $v ) {
 851              $qs[ $k ] = $v;
 852          }
 853      } else {
 854          $qs[ $args[0] ] = $args[1];
 855      }
 856  
 857      foreach ( $qs as $k => $v ) {
 858          if ( $v === false ) {
 859              unset( $qs[ $k ] );
 860          }
 861      }
 862  
 863      $ret = build_query( $qs );
 864      $ret = trim( $ret, '?' );
 865      $ret = preg_replace( '#=(&|$)#', '$1', $ret );
 866      $ret = $protocol . $base . $ret . $frag;
 867      $ret = rtrim( $ret, '?' );
 868      return $ret;
 869  }
 870  
 871  /**
 872   * Removes an item or items from a query string.
 873   *
 874   * @since 1.5.0
 875   *
 876   * @param string|array $key   Query key or keys to remove.
 877   * @param bool|string  $query Optional. When false uses the current URL. Default false.
 878   * @return string New URL query string.
 879   */
 880  function remove_query_arg( $key, $query = false ) {
 881      if ( is_array( $key ) ) { // removing multiple keys
 882          foreach ( $key as $k ) {
 883              $query = add_query_arg( $k, false, $query );
 884          }
 885          return $query;
 886      }
 887      return add_query_arg( $key, false, $query );
 888  }
 889  
 890  /**
 891   * Returns an array of single-use query variable names that can be removed from a URL.
 892   *
 893   * @since 4.4.0
 894   *
 895   * @return array An array of parameters to remove from the URL.
 896   */
 897  function wp_removable_query_args() {
 898      $removable_query_args = array(
 899          'activate',
 900          'activated',
 901          'approved',
 902          'deactivate',
 903          'deleted',
 904          'disabled',
 905          'enabled',
 906          'error',
 907          'hotkeys_highlight_first',
 908          'hotkeys_highlight_last',
 909          'locked',
 910          'message',
 911          'same',
 912          'saved',
 913          'settings-updated',
 914          'skipped',
 915          'spammed',
 916          'trashed',
 917          'unspammed',
 918          'untrashed',
 919          'update',
 920          'updated',
 921          'wp-post-new-reload',
 922      );
 923  
 924      /**
 925       * Filters the list of query variables to remove.
 926       *
 927       * @since 4.2.0
 928       *
 929       * @param array $removable_query_args An array of query variables to remove from a URL.
 930       */
 931      return apply_filters( 'removable_query_args', $removable_query_args );
 932  }
 933  
 934  /**
 935   * Walks the array while sanitizing the contents.
 936   *
 937   * @since 0.71
 938   *
 939   * @param array $array Array to walk while sanitizing contents.
 940   * @return array Sanitized $array.
 941   */
 942  function add_magic_quotes( $array ) {
 943      foreach ( (array) $array as $k => $v ) {
 944          if ( is_array( $v ) ) {
 945              $array[ $k ] = add_magic_quotes( $v );
 946          } else {
 947              $array[ $k ] = addslashes( $v );
 948          }
 949      }
 950      return $array;
 951  }
 952  
 953  /**
 954   * HTTP request for URI to retrieve content.
 955   *
 956   * @since 1.5.1
 957   *
 958   * @see wp_safe_remote_get()
 959   *
 960   * @param string $uri URI/URL of web page to retrieve.
 961   * @return false|string HTTP content. False on failure.
 962   */
 963  function wp_remote_fopen( $uri ) {
 964      $parsed_url = @parse_url( $uri );
 965  
 966      if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
 967          return false;
 968      }
 969  
 970      $options            = array();
 971      $options['timeout'] = 10;
 972  
 973      $response = wp_safe_remote_get( $uri, $options );
 974  
 975      if ( is_wp_error( $response ) ) {
 976          return false;
 977      }
 978  
 979      return wp_remote_retrieve_body( $response );
 980  }
 981  
 982  /**
 983   * Set up the WordPress query.
 984   *
 985   * @since 2.0.0
 986   *
 987   * @global WP       $wp_locale
 988   * @global WP_Query $wp_query
 989   * @global WP_Query $wp_the_query
 990   *
 991   * @param string|array $query_vars Default WP_Query arguments.
 992   */
 993  function wp( $query_vars = '' ) {
 994      global $wp, $wp_query, $wp_the_query;
 995      $wp->main( $query_vars );
 996  
 997      if ( ! isset( $wp_the_query ) ) {
 998          $wp_the_query = $wp_query;
 999      }
1000  }
1001  
1002  /**
1003   * Retrieve the description for the HTTP status.
1004   *
1005   * @since 2.3.0
1006   * @since 3.9.0 Added status codes 418, 428, 429, 431, and 511.
1007   * @since 4.5.0 Added status codes 308, 421, and 451.
1008   * @since 5.0.0 Added status code 103.
1009   *
1010   * @global array $wp_header_to_desc
1011   *
1012   * @param int $code HTTP status code.
1013   * @return string Empty string if not found, or description if found.
1014   */
1015  function get_status_header_desc( $code ) {
1016      global $wp_header_to_desc;
1017  
1018      $code = absint( $code );
1019  
1020      if ( ! isset( $wp_header_to_desc ) ) {
1021          $wp_header_to_desc = array(
1022              100 => 'Continue',
1023              101 => 'Switching Protocols',
1024              102 => 'Processing',
1025              103 => 'Early Hints',
1026  
1027              200 => 'OK',
1028              201 => 'Created',
1029              202 => 'Accepted',
1030              203 => 'Non-Authoritative Information',
1031              204 => 'No Content',
1032              205 => 'Reset Content',
1033              206 => 'Partial Content',
1034              207 => 'Multi-Status',
1035              226 => 'IM Used',
1036  
1037              300 => 'Multiple Choices',
1038              301 => 'Moved Permanently',
1039              302 => 'Found',
1040              303 => 'See Other',
1041              304 => 'Not Modified',
1042              305 => 'Use Proxy',
1043              306 => 'Reserved',
1044              307 => 'Temporary Redirect',
1045              308 => 'Permanent Redirect',
1046  
1047              400 => 'Bad Request',
1048              401 => 'Unauthorized',
1049              402 => 'Payment Required',
1050              403 => 'Forbidden',
1051              404 => 'Not Found',
1052              405 => 'Method Not Allowed',
1053              406 => 'Not Acceptable',
1054              407 => 'Proxy Authentication Required',
1055              408 => 'Request Timeout',
1056              409 => 'Conflict',
1057              410 => 'Gone',
1058              411 => 'Length Required',
1059              412 => 'Precondition Failed',
1060              413 => 'Request Entity Too Large',
1061              414 => 'Request-URI Too Long',
1062              415 => 'Unsupported Media Type',
1063              416 => 'Requested Range Not Satisfiable',
1064              417 => 'Expectation Failed',
1065              418 => 'I\'m a teapot',
1066              421 => 'Misdirected Request',
1067              422 => 'Unprocessable Entity',
1068              423 => 'Locked',
1069              424 => 'Failed Dependency',
1070              426 => 'Upgrade Required',
1071              428 => 'Precondition Required',
1072              429 => 'Too Many Requests',
1073              431 => 'Request Header Fields Too Large',
1074              451 => 'Unavailable For Legal Reasons',
1075  
1076              500 => 'Internal Server Error',
1077              501 => 'Not Implemented',
1078              502 => 'Bad Gateway',
1079              503 => 'Service Unavailable',
1080              504 => 'Gateway Timeout',
1081              505 => 'HTTP Version Not Supported',
1082              506 => 'Variant Also Negotiates',
1083              507 => 'Insufficient Storage',
1084              510 => 'Not Extended',
1085              511 => 'Network Authentication Required',
1086          );
1087      }
1088  
1089      if ( isset( $wp_header_to_desc[ $code ] ) ) {
1090          return $wp_header_to_desc[ $code ];
1091      } else {
1092          return '';
1093      }
1094  }
1095  
1096  /**
1097   * Set HTTP status header.
1098   *
1099   * @since 2.0.0
1100   * @since 4.4.0 Added the `$description` parameter.
1101   *
1102   * @see get_status_header_desc()
1103   *
1104   * @param int    $code        HTTP status code.
1105   * @param string $description Optional. A custom description for the HTTP status.
1106   */
1107  function status_header( $code, $description = '' ) {
1108      if ( ! $description ) {
1109          $description = get_status_header_desc( $code );
1110      }
1111  
1112      if ( empty( $description ) ) {
1113          return;
1114      }
1115  
1116      $protocol      = wp_get_server_protocol();
1117      $status_header = "$protocol $code $description";
1118      if ( function_exists( 'apply_filters' ) ) {
1119  
1120          /**
1121           * Filters an HTTP status header.
1122           *
1123           * @since 2.2.0
1124           *
1125           * @param string $status_header HTTP status header.
1126           * @param int    $code          HTTP status code.
1127           * @param string $description   Description for the status code.
1128           * @param string $protocol      Server protocol.
1129           */
1130          $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
1131      }
1132  
1133      @header( $status_header, true, $code );
1134  }
1135  
1136  /**
1137   * Get the header information to prevent caching.
1138   *
1139   * The several different headers cover the different ways cache prevention
1140   * is handled by different browsers
1141   *
1142   * @since 2.8.0
1143   *
1144   * @return array The associative array of header names and field values.
1145   */
1146  function wp_get_nocache_headers() {
1147      $headers = array(
1148          'Expires'       => 'Wed, 11 Jan 1984 05:00:00 GMT',
1149          'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
1150      );
1151  
1152      if ( function_exists( 'apply_filters' ) ) {
1153          /**
1154           * Filters the cache-controlling headers.
1155           *
1156           * @since 2.8.0
1157           *
1158           * @see wp_get_nocache_headers()
1159           *
1160           * @param array $headers {
1161           *     Header names and field values.
1162           *
1163           *     @type string $Expires       Expires header.
1164           *     @type string $Cache-Control Cache-Control header.
1165           * }
1166           */
1167          $headers = (array) apply_filters( 'nocache_headers', $headers );
1168      }
1169      $headers['Last-Modified'] = false;
1170      return $headers;
1171  }
1172  
1173  /**
1174   * Set the headers to prevent caching for the different browsers.
1175   *
1176   * Different browsers support different nocache headers, so several
1177   * headers must be sent so that all of them get the point that no
1178   * caching should occur.
1179   *
1180   * @since 2.0.0
1181   *
1182   * @see wp_get_nocache_headers()
1183   */
1184  function nocache_headers() {
1185      $headers = wp_get_nocache_headers();
1186  
1187      unset( $headers['Last-Modified'] );
1188  
1189      // In PHP 5.3+, make sure we are not sending a Last-Modified header.
1190      if ( function_exists( 'header_remove' ) ) {
1191          @header_remove( 'Last-Modified' );
1192      } else {
1193          // In PHP 5.2, send an empty Last-Modified header, but only as a
1194          // last resort to override a header already sent. #WP23021
1195          foreach ( headers_list() as $header ) {
1196              if ( 0 === stripos( $header, 'Last-Modified' ) ) {
1197                  $headers['Last-Modified'] = '';
1198                  break;
1199              }
1200          }
1201      }
1202  
1203      foreach ( $headers as $name => $field_value ) {
1204          @header( "{$name}: {$field_value}" );
1205      }
1206  }
1207  
1208  /**
1209   * Set the headers for caching for 10 days with JavaScript content type.
1210   *
1211   * @since 2.1.0
1212   */
1213  function cache_javascript_headers() {
1214      $expiresOffset = 10 * DAY_IN_SECONDS;
1215  
1216      header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) );
1217      header( 'Vary: Accept-Encoding' ); // Handle proxies
1218      header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiresOffset ) . ' GMT' );
1219  }
1220  
1221  /**
1222   * Retrieve the number of database queries during the WordPress execution.
1223   *
1224   * @since 2.0.0
1225   *
1226   * @global wpdb $wpdb WordPress database abstraction object.
1227   *
1228   * @return int Number of database queries.
1229   */
1230  function get_num_queries() {
1231      global $wpdb;
1232      return $wpdb->num_queries;
1233  }
1234  
1235  /**
1236   * Whether input is yes or no.
1237   *
1238   * Must be 'y' to be true.
1239   *
1240   * @since 1.0.0
1241   *
1242   * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
1243   * @return bool True if yes, false on anything else.
1244   */
1245  function bool_from_yn( $yn ) {
1246      return ( strtolower( $yn ) == 'y' );
1247  }
1248  
1249  /**
1250   * Load the feed template from the use of an action hook.
1251   *
1252   * If the feed action does not have a hook, then the function will die with a
1253   * message telling the visitor that the feed is not valid.
1254   *
1255   * It is better to only have one hook for each feed.
1256   *
1257   * @since 2.1.0
1258   *
1259   * @global WP_Query $wp_query Used to tell if the use a comment feed.
1260   */
1261  function do_feed() {
1262      global $wp_query;
1263  
1264      $feed = get_query_var( 'feed' );
1265  
1266      // Remove the pad, if present.
1267      $feed = preg_replace( '/^_+/', '', $feed );
1268  
1269      if ( $feed == '' || $feed == 'feed' ) {
1270          $feed = get_default_feed();
1271      }
1272  
1273      if ( ! has_action( "do_feed_{$feed}" ) ) {
1274          wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
1275      }
1276  
1277      /**
1278       * Fires once the given feed is loaded.
1279       *
1280       * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
1281       * Possible values include: 'rdf', 'rss', 'rss2', and 'atom'.
1282       *
1283       * @since 2.1.0
1284       * @since 4.4.0 The `$feed` parameter was added.
1285       *
1286       * @param bool   $is_comment_feed Whether the feed is a comment feed.
1287       * @param string $feed            The feed name.
1288       */
1289      do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
1290  }
1291  
1292  /**
1293   * Load the RDF RSS 0.91 Feed template.
1294   *
1295   * @since 2.1.0
1296   *
1297   * @see load_template()
1298   */
1299  function do_feed_rdf() {
1300      load_template( ABSPATH . WPINC . '/feed-rdf.php' );
1301  }
1302  
1303  /**
1304   * Load the RSS 1.0 Feed Template.
1305   *
1306   * @since 2.1.0
1307   *
1308   * @see load_template()
1309   */
1310  function do_feed_rss() {
1311      load_template( ABSPATH . WPINC . '/feed-rss.php' );
1312  }
1313  
1314  /**
1315   * Load either the RSS2 comment feed or the RSS2 posts feed.
1316   *
1317   * @since 2.1.0
1318   *
1319   * @see load_template()
1320   *
1321   * @param bool $for_comments True for the comment feed, false for normal feed.
1322   */
1323  function do_feed_rss2( $for_comments ) {
1324      if ( $for_comments ) {
1325          load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
1326      } else {
1327          load_template( ABSPATH . WPINC . '/feed-rss2.php' );
1328      }
1329  }
1330  
1331  /**
1332   * Load either Atom comment feed or Atom posts feed.
1333   *
1334   * @since 2.1.0
1335   *
1336   * @see load_template()
1337   *
1338   * @param bool $for_comments True for the comment feed, false for normal feed.
1339   */
1340  function do_feed_atom( $for_comments ) {
1341      if ( $for_comments ) {
1342          load_template( ABSPATH . WPINC . '/feed-atom-comments.php' );
1343      } else {
1344          load_template( ABSPATH . WPINC . '/feed-atom.php' );
1345      }
1346  }
1347  
1348  /**
1349   * Display the robots.txt file content.
1350   *
1351   * The echo content should be with usage of the permalinks or for creating the
1352   * robots.txt file.
1353   *
1354   * @since 2.1.0
1355   */
1356  function do_robots() {
1357      header( 'Content-Type: text/plain; charset=utf-8' );
1358  
1359      /**
1360       * Fires when displaying the robots.txt file.
1361       *
1362       * @since 2.1.0
1363       */
1364      do_action( 'do_robotstxt' );
1365  
1366      $output = "User-agent: *\n";
1367      $public = get_option( 'blog_public' );
1368      if ( '0' == $public ) {
1369          $output .= "Disallow: /\n";
1370      } else {
1371          $site_url = parse_url( site_url() );
1372          $path     = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
1373          $output  .= "Disallow: $path/wp-admin/\n";
1374          $output  .= "Allow: $path/wp-admin/admin-ajax.php\n";
1375      }
1376  
1377      /**
1378       * Filters the robots.txt output.
1379       *
1380       * @since 3.0.0
1381       *
1382       * @param string $output Robots.txt output.
1383       * @param bool   $public Whether the site is considered "public".
1384       */
1385      echo apply_filters( 'robots_txt', $output, $public );
1386  }
1387  
1388  /**
1389   * Determines whether WordPress is already installed.
1390   *
1391   * The cache will be checked first. If you have a cache plugin, which saves
1392   * the cache values, then this will work. If you use the default WordPress
1393   * cache, and the database goes away, then you might have problems.
1394   *
1395   * Checks for the 'siteurl' option for whether WordPress is installed.
1396   *
1397   * For more information on this and similar theme functions, check out
1398   * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
1399   * Conditional Tags} article in the Theme Developer Handbook.
1400   *
1401   * @since 2.1.0
1402   *
1403   * @global wpdb $wpdb WordPress database abstraction object.
1404   *
1405   * @return bool Whether the site is already installed.
1406   */
1407  function is_blog_installed() {
1408      global $wpdb;
1409  
1410      /*
1411       * Check cache first. If options table goes away and we have true
1412       * cached, oh well.
1413       */
1414      if ( wp_cache_get( 'is_blog_installed' ) ) {
1415          return true;
1416      }
1417  
1418      $suppress = $wpdb->suppress_errors();
1419      if ( ! wp_installing() ) {
1420          $alloptions = wp_load_alloptions();
1421      }
1422      // If siteurl is not set to autoload, check it specifically
1423      if ( ! isset( $alloptions['siteurl'] ) ) {
1424          $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
1425      } else {
1426          $installed = $alloptions['siteurl'];
1427      }
1428      $wpdb->suppress_errors( $suppress );
1429  
1430      $installed = ! empty( $installed );
1431      wp_cache_set( 'is_blog_installed', $installed );
1432  
1433      if ( $installed ) {
1434          return true;
1435      }
1436  
1437      // If visiting repair.php, return true and let it take over.
1438      if ( defined( 'WP_REPAIRING' ) ) {
1439          return true;
1440      }
1441  
1442      $suppress = $wpdb->suppress_errors();
1443  
1444      /*
1445       * Loop over the WP tables. If none exist, then scratch installation is allowed.
1446       * If one or more exist, suggest table repair since we got here because the
1447       * options table could not be accessed.
1448       */
1449      $wp_tables = $wpdb->tables();
1450      foreach ( $wp_tables as $table ) {
1451          // The existence of custom user tables shouldn't suggest an insane state or prevent a clean installation.
1452          if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table ) {
1453              continue;
1454          }
1455          if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table ) {
1456              continue;
1457          }
1458  
1459          if ( ! $wpdb->get_results( "DESCRIBE $table;" ) ) {
1460              continue;
1461          }
1462  
1463          // One or more tables exist. We are insane.
1464  
1465          wp_load_translations_early();
1466  
1467          // Die with a DB error.
1468          $wpdb->error = sprintf(
1469              /* translators: %s: database repair URL */
1470              __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ),
1471              'maint/repair.php?referrer=is_blog_installed'
1472          );
1473  
1474          dead_db();
1475      }
1476  
1477      $wpdb->suppress_errors( $suppress );
1478  
1479      wp_cache_set( 'is_blog_installed', false );
1480  
1481      return false;
1482  }
1483  
1484  /**
1485   * Retrieve URL with nonce added to URL query.
1486   *
1487   * @since 2.0.4
1488   *
1489   * @param string     $actionurl URL to add nonce action.
1490   * @param int|string $action    Optional. Nonce action name. Default -1.
1491   * @param string     $name      Optional. Nonce name. Default '_wpnonce'.
1492   * @return string Escaped URL with nonce action added.
1493   */
1494  function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
1495      $actionurl = str_replace( '&amp;', '&', $actionurl );
1496      return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
1497  }
1498  
1499  /**
1500   * Retrieve or display nonce hidden field for forms.
1501   *
1502   * The nonce field is used to validate that the contents of the form came from
1503   * the location on the current site and not somewhere else. The nonce does not
1504   * offer absolute protection, but should protect against most cases. It is very
1505   * important to use nonce field in forms.
1506   *
1507   * The $action and $name are optional, but if you want to have better security,
1508   * it is strongly suggested to set those two parameters. It is easier to just
1509   * call the function without any parameters, because validation of the nonce
1510   * doesn't require any parameters, but since crackers know what the default is
1511   * it won't be difficult for them to find a way around your nonce and cause
1512   * damage.
1513   *
1514   * The input name will be whatever $name value you gave. The input value will be
1515   * the nonce creation value.
1516   *
1517   * @since 2.0.4
1518   *
1519   * @param int|string $action  Optional. Action name. Default -1.
1520   * @param string     $name    Optional. Nonce name. Default '_wpnonce'.
1521   * @param bool       $referer Optional. Whether to set the referer field for validation. Default true.
1522   * @param bool       $echo    Optional. Whether to display or return hidden form field. Default true.
1523   * @return string Nonce field HTML markup.
1524   */
1525  function wp_nonce_field( $action = -1, $name = '_wpnonce', $referer = true, $echo = true ) {
1526      $name        = esc_attr( $name );
1527      $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
1528  
1529      if ( $referer ) {
1530          $nonce_field .= wp_referer_field( false );
1531      }
1532  
1533      if ( $echo ) {
1534          echo $nonce_field;
1535      }
1536  
1537      return $nonce_field;
1538  }
1539  
1540  /**
1541   * Retrieve or display referer hidden field for forms.
1542   *
1543   * The referer link is the current Request URI from the server super global. The
1544   * input name is '_wp_http_referer', in case you wanted to check manually.
1545   *
1546   * @since 2.0.4
1547   *
1548   * @param bool $echo Optional. Whether to echo or return the referer field. Default true.
1549   * @return string Referer field HTML markup.
1550   */
1551  function wp_referer_field( $echo = true ) {
1552      $referer_field = '<input type="hidden" name="_wp_http_referer" value="' . esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
1553  
1554      if ( $echo ) {
1555          echo $referer_field;
1556      }
1557      return $referer_field;
1558  }
1559  
1560  /**
1561   * Retrieve or display original referer hidden field for forms.
1562   *
1563   * The input name is '_wp_original_http_referer' and will be either the same
1564   * value of wp_referer_field(), if that was posted already or it will be the
1565   * current page, if it doesn't exist.
1566   *
1567   * @since 2.0.4
1568   *
1569   * @param bool   $echo         Optional. Whether to echo the original http referer. Default true.
1570   * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
1571   *                             Default 'current'.
1572   * @return string Original referer field.
1573   */
1574  function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
1575      if ( ! $ref = wp_get_original_referer() ) {
1576          $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
1577      }
1578      $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
1579      if ( $echo ) {
1580          echo $orig_referer_field;
1581      }
1582      return $orig_referer_field;
1583  }
1584  
1585  /**
1586   * Retrieve referer from '_wp_http_referer' or HTTP referer.
1587   *
1588   * If it's the same as the current request URL, will return false.
1589   *
1590   * @since 2.0.4
1591   *
1592   * @return false|string False on failure. Referer URL on success.
1593   */
1594  function wp_get_referer() {
1595      if ( ! function_exists( 'wp_validate_redirect' ) ) {
1596          return false;
1597      }
1598  
1599      $ref = wp_get_raw_referer();
1600  
1601      if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) && $ref !== home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) ) {
1602          return wp_validate_redirect( $ref, false );
1603      }
1604  
1605      return false;
1606  }
1607  
1608  /**
1609   * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
1610   *
1611   * Do not use for redirects, use wp_get_referer() instead.
1612   *
1613   * @since 4.5.0
1614   *
1615   * @return string|false Referer URL on success, false on failure.
1616   */
1617  function wp_get_raw_referer() {
1618      if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
1619          return wp_unslash( $_REQUEST['_wp_http_referer'] );
1620      } elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
1621          return wp_unslash( $_SERVER['HTTP_REFERER'] );
1622      }
1623  
1624      return false;
1625  }
1626  
1627  /**
1628   * Retrieve original referer that was posted, if it exists.
1629   *
1630   * @since 2.0.4
1631   *
1632   * @return string|false False if no original referer or original referer if set.
1633   */
1634  function wp_get_original_referer() {
1635      if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) ) {
1636          return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
1637      }
1638      return false;
1639  }
1640  
1641  /**
1642   * Recursive directory creation based on full path.
1643   *
1644   * Will attempt to set permissions on folders.
1645   *
1646   * @since 2.0.1
1647   *
1648   * @param string $target Full path to attempt to create.
1649   * @return bool Whether the path was created. True if path already exists.
1650   */
1651  function wp_mkdir_p( $target ) {
1652      $wrapper = null;
1653  
1654      // Strip the protocol.
1655      if ( wp_is_stream( $target ) ) {
1656          list( $wrapper, $target ) = explode( '://', $target, 2 );
1657      }
1658  
1659      // From php.net/mkdir user contributed notes.
1660      $target = str_replace( '//', '/', $target );
1661  
1662      // Put the wrapper back on the target.
1663      if ( $wrapper !== null ) {
1664          $target = $wrapper . '://' . $target;
1665      }
1666  
1667      /*
1668       * Safe mode fails with a trailing slash under certain PHP versions.
1669       * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
1670       */
1671      $target = rtrim( $target, '/' );
1672      if ( empty( $target ) ) {
1673          $target = '/';
1674      }
1675  
1676      if ( file_exists( $target ) ) {
1677          return @is_dir( $target );
1678      }
1679  
1680      // We need to find the permissions of the parent folder that exists and inherit that.
1681      $target_parent = dirname( $target );
1682      while ( '.' != $target_parent && ! is_dir( $target_parent ) && dirname( $target_parent ) !== $target_parent ) {
1683          $target_parent = dirname( $target_parent );
1684      }
1685  
1686      // Get the permission bits.
1687      if ( $stat = @stat( $target_parent ) ) {
1688          $dir_perms = $stat['mode'] & 0007777;
1689      } else {
1690          $dir_perms = 0777;
1691      }
1692  
1693      if ( @mkdir( $target, $dir_perms, true ) ) {
1694  
1695          /*
1696           * If a umask is set that modifies $dir_perms, we'll have to re-set
1697           * the $dir_perms correctly with chmod()
1698           */
1699          if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
1700              $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
1701              for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
1702                  @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
1703              }
1704          }
1705  
1706          return true;
1707      }
1708  
1709      return false;
1710  }
1711  
1712  /**
1713   * Test if a given filesystem path is absolute.
1714   *
1715   * For example, '/foo/bar', or 'c:\windows'.
1716   *
1717   * @since 2.5.0
1718   *
1719   * @param string $path File path.
1720   * @return bool True if path is absolute, false is not absolute.
1721   */
1722  function path_is_absolute( $path ) {
1723      /*
1724       * This is definitive if true but fails if $path does not exist or contains
1725       * a symbolic link.
1726       */
1727      if ( realpath( $path ) == $path ) {
1728          return true;
1729      }
1730  
1731      if ( strlen( $path ) == 0 || $path[0] == '.' ) {
1732          return false;
1733      }
1734  
1735      // Windows allows absolute paths like this.
1736      if ( preg_match( '#^[a-zA-Z]:\\\\#', $path ) ) {
1737          return true;
1738      }
1739  
1740      // A path starting with / or \ is absolute; anything else is relative.
1741      return ( $path[0] == '/' || $path[0] == '\\' );
1742  }
1743  
1744  /**
1745   * Join two filesystem paths together.
1746   *
1747   * For example, 'give me $path relative to $base'. If the $path is absolute,
1748   * then it the full path is returned.
1749   *
1750   * @since 2.5.0
1751   *
1752   * @param string $base Base path.
1753   * @param string $path Path relative to $base.
1754   * @return string The path with the base or absolute path.
1755   */
1756  function path_join( $base, $path ) {
1757      if ( path_is_absolute( $path ) ) {
1758          return $path;
1759      }
1760  
1761      return rtrim( $base, '/' ) . '/' . ltrim( $path, '/' );
1762  }
1763  
1764  /**
1765   * Normalize a filesystem path.
1766   *
1767   * On windows systems, replaces backslashes with forward slashes
1768   * and forces upper-case drive letters.
1769   * Allows for two leading slashes for Windows network shares, but
1770   * ensures that all other duplicate slashes are reduced to a single.
1771   *
1772   * @since 3.9.0
1773   * @since 4.4.0 Ensures upper-case drive letters on Windows systems.
1774   * @since 4.5.0 Allows for Windows network shares.
1775   * @since 5.0.0 Allows for PHP file wrappers.
1776   *
1777   * @param string $path Path to normalize.
1778   * @return string Normalized path.
1779   */
1780  function wp_normalize_path( $path ) {
1781      $wrapper = '';
1782      if ( wp_is_stream( $path ) ) {
1783          list( $wrapper, $path ) = explode( '://', $path, 2 );
1784          $wrapper .= '://';
1785      }
1786  
1787      // Standardise all paths to use /
1788      $path = str_replace( '\\', '/', $path );
1789  
1790      // Replace multiple slashes down to a singular, allowing for network shares having two slashes.
1791      $path = preg_replace( '|(?<=.)/+|', '/', $path );
1792  
1793      // Windows paths should uppercase the drive letter
1794      if ( ':' === substr( $path, 1, 1 ) ) {
1795          $path = ucfirst( $path );
1796      }
1797  
1798      return $wrapper . $path;
1799  }
1800  
1801  /**
1802   * Determine a writable directory for temporary files.
1803   *
1804   * Function's preference is the return value of sys_get_temp_dir(),
1805   * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1806   * before finally defaulting to /tmp/
1807   *
1808   * In the event that this function does not find a writable location,
1809   * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
1810   *
1811   * @since 2.5.0
1812   *
1813   * @staticvar string $temp
1814   *
1815   * @return string Writable temporary directory.
1816   */
1817  function get_temp_dir() {
1818      static $temp = '';
1819      if ( defined( 'WP_TEMP_DIR' ) ) {
1820          return trailingslashit( WP_TEMP_DIR );
1821      }
1822  
1823      if ( $temp ) {
1824          return trailingslashit( $temp );
1825      }
1826  
1827      if ( function_exists( 'sys_get_temp_dir' ) ) {
1828          $temp = sys_get_temp_dir();
1829          if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
1830              return trailingslashit( $temp );
1831          }
1832      }
1833  
1834      $temp = ini_get( 'upload_tmp_dir' );
1835      if ( @is_dir( $temp ) && wp_is_writable( $temp ) ) {
1836          return trailingslashit( $temp );
1837      }
1838  
1839      $temp = WP_CONTENT_DIR . '/';
1840      if ( is_dir( $temp ) && wp_is_writable( $temp ) ) {
1841          return $temp;
1842      }
1843  
1844      return '/tmp/';
1845  }
1846  
1847  /**
1848   * Determine if a directory is writable.
1849   *
1850   * This function is used to work around certain ACL issues in PHP primarily
1851   * affecting Windows Servers.
1852   *
1853   * @since 3.6.0
1854   *
1855   * @see win_is_writable()
1856   *
1857   * @param string $path Path to check for write-ability.
1858   * @return bool Whether the path is writable.
1859   */
1860  function wp_is_writable( $path ) {
1861      if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
1862          return win_is_writable( $path );
1863      } else {
1864          return @is_writable( $path );
1865      }
1866  }
1867  
1868  /**
1869   * Workaround for Windows bug in is_writable() function
1870   *
1871   * PHP has issues with Windows ACL's for determine if a
1872   * directory is writable or not, this works around them by
1873   * checking the ability to open files rather than relying
1874   * upon PHP to interprate the OS ACL.
1875   *
1876   * @since 2.8.0
1877   *
1878   * @see https://bugs.php.net/bug.php?id=27609
1879   * @see https://bugs.php.net/bug.php?id=30931
1880   *
1881   * @param string $path Windows path to check for write-ability.
1882   * @return bool Whether the path is writable.
1883   */
1884  function win_is_writable( $path ) {
1885  
1886      if ( $path[ strlen( $path ) - 1 ] == '/' ) { // if it looks like a directory, check a random file within the directory
1887          return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp' );
1888      } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
1889          return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1890      }
1891      // check tmp file for read/write capabilities
1892      $should_delete_tmp_file = ! file_exists( $path );
1893      $f                      = @fopen( $path, 'a' );
1894      if ( $f === false ) {
1895          return false;
1896      }
1897      fclose( $f );
1898      if ( $should_delete_tmp_file ) {
1899          unlink( $path );
1900      }
1901      return true;
1902  }
1903  
1904  /**
1905   * Retrieves uploads directory information.
1906   *
1907   * Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
1908   * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
1909   * when not uploading files.
1910   *
1911   * @since 4.5.0
1912   *
1913   * @see wp_upload_dir()
1914   *
1915   * @return array See wp_upload_dir() for description.
1916   */
1917  function wp_get_upload_dir() {
1918      return wp_upload_dir( null, false );
1919  }
1920  
1921  /**
1922   * Get an array containing the current upload directory's path and url.
1923   *
1924   * Checks the 'upload_path' option, which should be from the web root folder,
1925   * and if it isn't empty it will be used. If it is empty, then the path will be
1926   * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1927   * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1928   *
1929   * The upload URL path is set either by the 'upload_url_path' option or by using
1930   * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1931   *
1932   * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1933   * the administration settings panel), then the time will be used. The format
1934   * will be year first and then month.
1935   *
1936   * If the path couldn't be created, then an error will be returned with the key
1937   * 'error' containing the error message. The error suggests that the parent
1938   * directory is not writable by the server.
1939   *
1940   * On success, the returned array will have many indices:
1941   * 'path' - base directory and sub directory or full path to upload directory.
1942   * 'url' - base url and sub directory or absolute URL to upload directory.
1943   * 'subdir' - sub directory if uploads use year/month folders option is on.
1944   * 'basedir' - path without subdir.
1945   * 'baseurl' - URL path without subdir.
1946   * 'error' - false or error message.
1947   *
1948   * @since 2.0.0
1949   * @uses _wp_upload_dir()
1950   *
1951   * @staticvar array $cache
1952   * @staticvar array $tested_paths
1953   *
1954   * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1955   * @param bool   $create_dir Optional. Whether to check and create the uploads directory.
1956   *                           Default true for backward compatibility.
1957   * @param bool   $refresh_cache Optional. Whether to refresh the cache. Default false.
1958   * @return array See above for description.
1959   */
1960  function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
1961      static $cache = array(), $tested_paths = array();
1962  
1963      $key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );
1964  
1965      if ( $refresh_cache || empty( $cache[ $key ] ) ) {
1966          $cache[ $key ] = _wp_upload_dir( $time );
1967      }
1968  
1969      /**
1970       * Filters the uploads directory data.
1971       *
1972       * @since 2.0.0
1973       *
1974       * @param array $uploads Array of upload directory data with keys of 'path',
1975       *                       'url', 'subdir, 'basedir', and 'error'.
1976       */
1977      $uploads = apply_filters( 'upload_dir', $cache[ $key ] );
1978  
1979      if ( $create_dir ) {
1980          $path = $uploads['path'];
1981  
1982          if ( array_key_exists( $path, $tested_paths ) ) {
1983              $uploads['error'] = $tested_paths[ $path ];
1984          } else {
1985              if ( ! wp_mkdir_p( $path ) ) {
1986                  if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) {
1987                      $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1988                  } else {
1989                      $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1990                  }
1991  
1992                  $uploads['error'] = sprintf(
1993                      /* translators: %s: directory path */
1994                      __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
1995                      esc_html( $error_path )
1996                  );
1997              }
1998  
1999              $tested_paths[ $path ] = $uploads['error'];
2000          }
2001      }
2002  
2003      return $uploads;
2004  }
2005  
2006  /**
2007   * A non-filtered, non-cached version of wp_upload_dir() that doesn't check the path.
2008   *
2009   * @since 4.5.0
2010   * @access private
2011   *
2012   * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
2013   * @return array See wp_upload_dir()
2014   */
2015  function _wp_upload_dir( $time = null ) {
2016      $siteurl     = get_option( 'siteurl' );
2017      $upload_path = trim( get_option( 'upload_path' ) );
2018  
2019      if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
2020          $dir = WP_CONTENT_DIR . '/uploads';
2021      } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
2022          // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
2023          $dir = path_join( ABSPATH, $upload_path );
2024      } else {
2025          $dir = $upload_path;
2026      }
2027  
2028      if ( ! $url = get_option( 'upload_url_path' ) ) {
2029          if ( empty( $upload_path ) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) {
2030              $url = WP_CONTENT_URL . '/uploads';
2031          } else {
2032              $url = trailingslashit( $siteurl ) . $upload_path;
2033          }
2034      }
2035  
2036      /*
2037       * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
2038       * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
2039       */
2040      if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
2041          $dir = ABSPATH . UPLOADS;
2042          $url = trailingslashit( $siteurl ) . UPLOADS;
2043      }
2044  
2045      // If multisite (and if not the main site in a post-MU network)
2046      if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
2047  
2048          if ( ! get_site_option( 'ms_files_rewriting' ) ) {
2049              /*
2050               * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
2051               * straightforward: Append sites/%d if we're not on the main site (for post-MU
2052               * networks). (The extra directory prevents a four-digit ID from conflicting with
2053               * a year-based directory for the main site. But if a MU-era network has disabled
2054               * ms-files rewriting manually, they don't need the extra directory, as they never
2055               * had wp-content/uploads for the main site.)
2056               */
2057  
2058              if ( defined( 'MULTISITE' ) ) {
2059                  $ms_dir = '/sites/' . get_current_blog_id();
2060              } else {
2061                  $ms_dir = '/' . get_current_blog_id();
2062              }
2063  
2064              $dir .= $ms_dir;
2065              $url .= $ms_dir;
2066  
2067          } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
2068              /*
2069               * Handle the old-form ms-files.php rewriting if the network still has that enabled.
2070               * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
2071               * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
2072               *    there, and
2073               * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
2074               *    the original blog ID.
2075               *
2076               * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
2077               * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
2078               * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
2079               * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
2080               */
2081  
2082              if ( defined( 'BLOGUPLOADDIR' ) ) {
2083                  $dir = untrailingslashit( BLOGUPLOADDIR );
2084              } else {
2085                  $dir = ABSPATH . UPLOADS;
2086              }
2087              $url = trailingslashit( $siteurl ) . 'files';
2088          }
2089      }
2090  
2091      $basedir = $dir;
2092      $baseurl = $url;
2093  
2094      $subdir = '';
2095      if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
2096          // Generate the yearly and monthly dirs
2097          if ( ! $time ) {
2098              $time = current_time( 'mysql' );
2099          }
2100          $y      = substr( $time, 0, 4 );
2101          $m      = substr( $time, 5, 2 );
2102          $subdir = "/$y/$m";
2103      }
2104  
2105      $dir .= $subdir;
2106      $url .= $subdir;
2107  
2108      return array(
2109          'path'    => $dir,
2110          'url'     => $url,
2111          'subdir'  => $subdir,
2112          'basedir' => $basedir,
2113          'baseurl' => $baseurl,
2114          'error'   => false,
2115      );
2116  }
2117  
2118  /**
2119   * Get a filename that is sanitized and unique for the given directory.
2120   *
2121   * If the filename is not unique, then a number will be added to the filename
2122   * before the extension, and will continue adding numbers until the filename is
2123   * unique.
2124   *
2125   * The callback is passed three parameters, the first one is the directory, the
2126   * second is the filename, and the third is the extension.
2127   *
2128   * @since 2.5.0
2129   *
2130   * @param string   $dir                      Directory.
2131   * @param string   $filename                 File name.
2132   * @param callable $unique_filename_callback Callback. Default null.
2133   * @return string New filename, if given wasn't unique.
2134   */
2135  function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
2136      // Sanitize the file name before we begin processing.
2137      $filename = sanitize_file_name( $filename );
2138  
2139      // Separate the filename into a name and extension.
2140      $ext  = pathinfo( $filename, PATHINFO_EXTENSION );
2141      $name = pathinfo( $filename, PATHINFO_BASENAME );
2142      if ( $ext ) {
2143          $ext = '.' . $ext;
2144      }
2145  
2146      // Edge case: if file is named '.ext', treat as an empty name.
2147      if ( $name === $ext ) {
2148          $name = '';
2149      }
2150  
2151      /*
2152       * Increment the file number until we have a unique file to save in $dir.
2153       * Use callback if supplied.
2154       */
2155      if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
2156          $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
2157      } else {
2158          $number = '';
2159  
2160          // Change '.ext' to lower case.
2161          if ( $ext && strtolower( $ext ) != $ext ) {
2162              $ext2      = strtolower( $ext );
2163              $filename2 = preg_replace( '|' . preg_quote( $ext ) . '$|', $ext2, $filename );
2164  
2165              // Check for both lower and upper case extension or image sub-sizes may be overwritten.
2166              while ( file_exists( $dir . "/$filename" ) || file_exists( $dir . "/$filename2" ) ) {
2167                  $new_number = (int) $number + 1;
2168                  $filename   = str_replace( array( "-$number$ext", "$number$ext" ), "-$new_number$ext", $filename );
2169                  $filename2  = str_replace( array( "-$number$ext2", "$number$ext2" ), "-$new_number$ext2", $filename2 );
2170                  $number     = $new_number;
2171              }
2172  
2173              /**
2174               * Filters the result when generating a unique file name.
2175               *
2176               * @since 4.5.0
2177               *
2178               * @param string        $filename                 Unique file name.
2179               * @param string        $ext                      File extension, eg. ".png".
2180               * @param string        $dir                      Directory path.
2181               * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
2182               */
2183              return apply_filters( 'wp_unique_filename', $filename2, $ext, $dir, $unique_filename_callback );
2184          }
2185  
2186          while ( file_exists( $dir . "/$filename" ) ) {
2187              $new_number = (int) $number + 1;
2188              if ( '' == "$number$ext" ) {
2189                  $filename = "$filename-" . $new_number;
2190              } else {
2191                  $filename = str_replace( array( "-$number$ext", "$number$ext" ), '-' . $new_number . $ext, $filename );
2192              }
2193              $number = $new_number;
2194          }
2195      }
2196  
2197      /** This filter is documented in wp-includes/functions.php */
2198      return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
2199  }
2200  
2201  /**
2202   * Create a file in the upload folder with given content.
2203   *
2204   * If there is an error, then the key 'error' will exist with the error message.
2205   * If success, then the key 'file' will have the unique file path, the 'url' key
2206   * will have the link to the new file. and the 'error' key will be set to false.
2207   *
2208   * This function will not move an uploaded file to the upload folder. It will
2209   * create a new file with the content in $bits parameter. If you move the upload
2210   * file, read the content of the uploaded file, and then you can give the
2211   * filename and content to this function, which will add it to the upload
2212   * folder.
2213   *
2214   * The permissions will be set on the new file automatically by this function.
2215   *
2216   * @since 2.0.0
2217   *
2218   * @param string       $name       Filename.
2219   * @param null|string  $deprecated Never used. Set to null.
2220   * @param mixed        $bits       File content
2221   * @param string       $time       Optional. Time formatted in 'yyyy/mm'. Default null.
2222   * @return array
2223   */
2224  function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
2225      if ( ! empty( $deprecated ) ) {
2226          _deprecated_argument( __FUNCTION__, '2.0.0' );
2227      }
2228  
2229      if ( empty( $name ) ) {
2230          return array( 'error' => __( 'Empty filename' ) );
2231      }
2232  
2233      $wp_filetype = wp_check_filetype( $name );
2234      if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) ) {
2235          return array( 'error' => __( 'Sorry, this file type is not permitted for security reasons.' ) );
2236      }
2237  
2238      $upload = wp_upload_dir( $time );
2239  
2240      if ( $upload['error'] !== false ) {
2241          return $upload;
2242      }
2243  
2244      /**
2245       * Filters whether to treat the upload bits as an error.
2246       *
2247       * Passing a non-array to the filter will effectively short-circuit preparing
2248       * the upload bits, returning that value instead.
2249       *
2250       * @since 3.0.0
2251       *
2252       * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
2253       */
2254      $upload_bits_error = apply_filters(
2255          'wp_upload_bits', array(
2256              'name' => $name,
2257              'bits' => $bits,
2258              'time' => $time,
2259          )
2260      );
2261      if ( ! is_array( $upload_bits_error ) ) {
2262          $upload['error'] = $upload_bits_error;
2263          return $upload;
2264      }
2265  
2266      $filename = wp_unique_filename( $upload['path'], $name );
2267  
2268      $new_file = $upload['path'] . "/$filename";
2269      if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
2270          if ( 0 === strpos( $upload['basedir'], ABSPATH ) ) {
2271              $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
2272          } else {
2273              $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
2274          }
2275  
2276          $message = sprintf(
2277              /* translators: %s: directory path */
2278              __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
2279              $error_path
2280          );
2281          return array( 'error' => $message );
2282      }
2283  
2284      $ifp = @ fopen( $new_file, 'wb' );
2285      if ( ! $ifp ) {
2286          return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
2287      }
2288  
2289      @fwrite( $ifp, $bits );
2290      fclose( $ifp );
2291      clearstatcache();
2292  
2293      // Set correct file permissions
2294      $stat  = @ stat( dirname( $new_file ) );
2295      $perms = $stat['mode'] & 0007777;
2296      $perms = $perms & 0000666;
2297      @ chmod( $new_file, $perms );
2298      clearstatcache();
2299  
2300      // Compute the URL
2301      $url = $upload['url'] . "/$filename";
2302  
2303      /** This filter is documented in wp-admin/includes/file.php */
2304      return apply_filters(
2305          'wp_handle_upload', array(
2306              'file'  => $new_file,
2307              'url'   => $url,
2308              'type'  => $wp_filetype['type'],
2309              'error' => false,
2310          ), 'sideload'
2311      );
2312  }
2313  
2314  /**
2315   * Retrieve the file type based on the extension name.
2316   *
2317   * @since 2.5.0
2318   *
2319   * @param string $ext The extension to search.
2320   * @return string|void The file type, example: audio, video, document, spreadsheet, etc.
2321   */
2322  function wp_ext2type( $ext ) {
2323      $ext = strtolower( $ext );
2324  
2325      $ext2type = wp_get_ext_types();
2326      foreach ( $ext2type as $type => $exts ) {
2327          if ( in_array( $ext, $exts ) ) {
2328              return $type;
2329          }
2330      }
2331  }
2332  
2333  /**
2334   * Retrieve the file type from the file name.
2335   *
2336   * You can optionally define the mime array, if needed.
2337   *
2338   * @since 2.0.4
2339   *
2340   * @param string $filename File name or path.
2341   * @param array  $mimes    Optional. Key is the file extension with value as the mime type.
2342   * @return array Values with extension first and mime type.
2343   */
2344  function wp_check_filetype( $filename, $mimes = null ) {
2345      if ( empty( $mimes ) ) {
2346          $mimes = get_allowed_mime_types();
2347      }
2348      $type = false;
2349      $ext  = false;
2350  
2351      foreach ( $mimes as $ext_preg => $mime_match ) {
2352          $ext_preg = '!\.(' . $ext_preg . ')$!i';
2353          if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
2354              $type = $mime_match;
2355              $ext  = $ext_matches[1];
2356              break;
2357          }
2358      }
2359  
2360      return compact( 'ext', 'type' );
2361  }
2362  
2363  /**
2364   * Attempt to determine the real file type of a file.
2365   *
2366   * If unable to, the file name extension will be used to determine type.
2367   *
2368   * If it's determined that the extension does not match the file's real type,
2369   * then the "proper_filename" value will be set with a proper filename and extension.
2370   *
2371   * Currently this function only supports renaming images validated via wp_get_image_mime().
2372   *
2373   * @since 3.0.0
2374   *
2375   * @param string $file     Full path to the file.
2376   * @param string $filename The name of the file (may differ from $file due to $file being
2377   *                         in a tmp directory).
2378   * @param array   $mimes   Optional. Key is the file extension with value as the mime type.
2379   * @return array Values for the extension, MIME, and either a corrected filename or false
2380   *               if original $filename is valid.
2381   */
2382  function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
2383      $proper_filename = false;
2384  
2385      // Do basic extension validation and MIME mapping
2386      $wp_filetype = wp_check_filetype( $filename, $mimes );
2387      $ext         = $wp_filetype['ext'];
2388      $type        = $wp_filetype['type'];
2389  
2390      // We can't do any further validation without a file to work with
2391      if ( ! file_exists( $file ) ) {
2392          return compact( 'ext', 'type', 'proper_filename' );
2393      }
2394  
2395      $real_mime = false;
2396  
2397      // Validate image types.
2398      if ( $type && 0 === strpos( $type, 'image/' ) ) {
2399  
2400          // Attempt to figure out what type of image it actually is
2401          $real_mime = wp_get_image_mime( $file );
2402  
2403          if ( $real_mime && $real_mime != $type ) {
2404              /**
2405               * Filters the list mapping image mime types to their respective extensions.
2406               *
2407               * @since 3.0.0
2408               *
2409               * @param  array $mime_to_ext Array of image mime types and their matching extensions.
2410               */
2411              $mime_to_ext = apply_filters(
2412                  'getimagesize_mimes_to_exts', array(
2413                      'image/jpeg' => 'jpg',
2414                      'image/png'  => 'png',
2415                      'image/gif'  => 'gif',
2416                      'image/bmp'  => 'bmp',
2417                      'image/tiff' => 'tif',
2418                  )
2419              );
2420  
2421              // Replace whatever is after the last period in the filename with the correct extension
2422              if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
2423                  $filename_parts = explode( '.', $filename );
2424                  array_pop( $filename_parts );
2425                  $filename_parts[] = $mime_to_ext[ $real_mime ];
2426                  $new_filename     = implode( '.', $filename_parts );
2427  
2428                  if ( $new_filename != $filename ) {
2429                      $proper_filename = $new_filename; // Mark that it changed
2430                  }
2431                  // Redefine the extension / MIME
2432                  $wp_filetype = wp_check_filetype( $new_filename, $mimes );
2433                  $ext         = $wp_filetype['ext'];
2434                  $type        = $wp_filetype['type'];
2435              } else {
2436                  // Reset $real_mime and try validating again.
2437                  $real_mime = false;
2438              }
2439          }
2440      }
2441  
2442      // Validate files that didn't get validated during previous checks.
2443      if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) {
2444          $finfo     = finfo_open( FILEINFO_MIME_TYPE );
2445          $real_mime = finfo_file( $finfo, $file );
2446          finfo_close( $finfo );
2447  
2448          /*
2449           * If $real_mime doesn't match what we're expecting, we need to do some extra
2450           * vetting of application mime types to make sure this type of file is allowed.
2451           * Other mime types are assumed to be safe, but should be considered unverified.
2452           */
2453          if ( $real_mime && ( $real_mime !== $type ) && ( 0 === strpos( $real_mime, 'application' ) ) ) {
2454              $allowed = get_allowed_mime_types();
2455  
2456              if ( ! in_array( $real_mime, $allowed ) ) {
2457                  $type = $ext = false;
2458              }
2459          }
2460      }
2461  
2462      /**
2463       * Filters the "real" file type of the given file.
2464       *
2465       * @since 3.0.0
2466       *
2467       * @param array  $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
2468       *                                          'proper_filename' keys.
2469       * @param string $file                      Full path to the file.
2470       * @param string $filename                  The name of the file (may differ from $file due to
2471       *                                          $file being in a tmp directory).
2472       * @param array  $mimes                     Key is the file extension with value as the mime type.
2473       */
2474      return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
2475  }
2476  
2477  /**
2478   * Returns the real mime type of an image file.
2479   *
2480   * This depends on exif_imagetype() or getimagesize() to determine real mime types.
2481   *
2482   * @since 4.7.1
2483   *
2484   * @param string $file Full path to the file.
2485   * @return string|false The actual mime type or false if the type cannot be determined.
2486   */
2487  function wp_get_image_mime( $file ) {
2488      /*
2489       * Use exif_imagetype() to check the mimetype if available or fall back to
2490       * getimagesize() if exif isn't avaialbe. If either function throws an Exception
2491       * we assume the file could not be validated.
2492       */
2493      try {
2494          if ( is_callable( 'exif_imagetype' ) ) {
2495              $imagetype = exif_imagetype( $file );
2496              $mime      = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
2497          } elseif ( function_exists( 'getimagesize' ) ) {
2498              $imagesize = getimagesize( $file );
2499              $mime      = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
2500          } else {
2501              $mime = false;
2502          }
2503      } catch ( Exception $e ) {
2504          $mime = false;
2505      }
2506  
2507      return $mime;
2508  }
2509  
2510  /**
2511   * Retrieve list of mime types and file extensions.
2512   *
2513   * @since 3.5.0
2514   * @since 4.2.0 Support was added for GIMP (xcf) files.
2515   *
2516   * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2517   */
2518  function wp_get_mime_types() {
2519      /**
2520       * Filters the list of mime types and file extensions.
2521       *
2522       * This filter should be used to add, not remove, mime types. To remove
2523       * mime types, use the {@see 'upload_mimes'} filter.
2524       *
2525       * @since 3.5.0
2526       *
2527       * @param array $wp_get_mime_types Mime types keyed by the file extension regex
2528       *                                 corresponding to those types.
2529       */
2530      return apply_filters(
2531          'mime_types', array(
2532              // Image formats.
2533              'jpg|jpeg|jpe'                 => 'image/jpeg',
2534              'gif'                          => 'image/gif',
2535              'png'                          => 'image/png',
2536              'bmp'                          => 'image/bmp',
2537              'tiff|tif'                     => 'image/tiff',
2538              'ico'                          => 'image/x-icon',
2539              // Video formats.
2540              'asf|asx'                      => 'video/x-ms-asf',
2541              'wmv'                          => 'video/x-ms-wmv',
2542              'wmx'                          => 'video/x-ms-wmx',
2543              'wm'                           => 'video/x-ms-wm',
2544              'avi'                          => 'video/avi',
2545              'divx'                         => 'video/divx',
2546              'flv'                          => 'video/x-flv',
2547              'mov|qt'                       => 'video/quicktime',
2548              'mpeg|mpg|mpe'                 => 'video/mpeg',
2549              'mp4|m4v'                      => 'video/mp4',
2550              'ogv'                          => 'video/ogg',
2551              'webm'                         => 'video/webm',
2552              'mkv'                          => 'video/x-matroska',
2553              '3gp|3gpp'                     => 'video/3gpp', // Can also be audio
2554              '3g2|3gp2'                     => 'video/3gpp2', // Can also be audio
2555              // Text formats.
2556              'txt|asc|c|cc|h|srt'           => 'text/plain',
2557              'csv'                          => 'text/csv',
2558              'tsv'                          => 'text/tab-separated-values',
2559              'ics'                          => 'text/calendar',
2560              'rtx'                          => 'text/richtext',
2561              'css'                          => 'text/css',
2562              'htm|html'                     => 'text/html',
2563              'vtt'                          => 'text/vtt',
2564              'dfxp'                         => 'application/ttaf+xml',
2565              // Audio formats.
2566              'mp3|m4a|m4b'                  => 'audio/mpeg',
2567              'aac'                          => 'audio/aac',
2568              'ra|ram'                       => 'audio/x-realaudio',
2569              'wav'                          => 'audio/wav',
2570              'ogg|oga'                      => 'audio/ogg',
2571              'flac'                         => 'audio/flac',
2572              'mid|midi'                     => 'audio/midi',
2573              'wma'                          => 'audio/x-ms-wma',
2574              'wax'                          => 'audio/x-ms-wax',
2575              'mka'                          => 'audio/x-matroska',
2576              // Misc application formats.
2577              'rtf'                          => 'application/rtf',
2578              'js'                           => 'application/javascript',
2579              'pdf'                          => 'application/pdf',
2580              'swf'                          => 'application/x-shockwave-flash',
2581              'class'                        => 'application/java',
2582              'tar'                          => 'application/x-tar',
2583              'zip'                          => 'application/zip',
2584              'gz|gzip'                      => 'application/x-gzip',
2585              'rar'                          => 'application/rar',
2586              '7z'                           => 'application/x-7z-compressed',
2587              'exe'                          => 'application/x-msdownload',
2588              'psd'                          => 'application/octet-stream',
2589              'xcf'                          => 'application/octet-stream',
2590              // MS Office formats.
2591              'doc'                          => 'application/msword',
2592              'pot|pps|ppt'                  => 'application/vnd.ms-powerpoint',
2593              'wri'                          => 'application/vnd.ms-write',
2594              'xla|xls|xlt|xlw'              => 'application/vnd.ms-excel',
2595              'mdb'                          => 'application/vnd.ms-access',
2596              'mpp'                          => 'application/vnd.ms-project',
2597              'docx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2598              'docm'                         => 'application/vnd.ms-word.document.macroEnabled.12',
2599              'dotx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2600              'dotm'                         => 'application/vnd.ms-word.template.macroEnabled.12',
2601              'xlsx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2602              'xlsm'                         => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2603              'xlsb'                         => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2604              'xltx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2605              'xltm'                         => 'application/vnd.ms-excel.template.macroEnabled.12',
2606              'xlam'                         => 'application/vnd.ms-excel.addin.macroEnabled.12',
2607              'pptx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2608              'pptm'                         => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2609              'ppsx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2610              'ppsm'                         => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2611              'potx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2612              'potm'                         => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2613              'ppam'                         => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2614              'sldx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2615              'sldm'                         => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2616              'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2617              'oxps'                         => 'application/oxps',
2618              'xps'                          => 'application/vnd.ms-xpsdocument',
2619              // OpenOffice formats.
2620              'odt'                          => 'application/vnd.oasis.opendocument.text',
2621              'odp'                          => 'application/vnd.oasis.opendocument.presentation',
2622              'ods'                          => 'application/vnd.oasis.opendocument.spreadsheet',
2623              'odg'                          => 'application/vnd.oasis.opendocument.graphics',
2624              'odc'                          => 'application/vnd.oasis.opendocument.chart',
2625              'odb'                          => 'application/vnd.oasis.opendocument.database',
2626              'odf'                          => 'application/vnd.oasis.opendocument.formula',
2627              // WordPerfect formats.
2628              'wp|wpd'                       => 'application/wordperfect',
2629              // iWork formats.
2630              'key'                          => 'application/vnd.apple.keynote',
2631              'numbers'                      => 'application/vnd.apple.numbers',
2632              'pages'                        => 'application/vnd.apple.pages',
2633          )
2634      );
2635  }
2636  
2637  /**
2638   * Retrieves the list of common file extensions and their types.
2639   *
2640   * @since 4.6.0
2641   *
2642   * @return array Array of file extensions types keyed by the type of file.
2643   */
2644  function wp_get_ext_types() {
2645  
2646      /**
2647       * Filters file type based on the extension name.
2648       *
2649       * @since 2.5.0
2650       *
2651       * @see wp_ext2type()
2652       *
2653       * @param array $ext2type Multi-dimensional array with extensions for a default set
2654       *                        of file types.
2655       */
2656      return apply_filters(
2657          'ext2type', array(
2658              'image'       => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico' ),
2659              'audio'       => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
2660              'video'       => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
2661              'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
2662              'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ),
2663              'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
2664              'text'        => array( 'asc', 'csv', 'tsv', 'txt' ),
2665              'archive'     => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ),
2666              'code'        => array( 'css', 'htm', 'html', 'php', 'js' ),
2667          )
2668      );
2669  }
2670  
2671  /**
2672   * Retrieve list of allowed mime types and file extensions.
2673   *
2674   * @since 2.8.6
2675   *
2676   * @param int|WP_User $user Optional. User to check. Defaults to current user.
2677   * @return array Array of mime types keyed by the file extension regex corresponding
2678   *               to those types.
2679   */
2680  function get_allowed_mime_types( $user = null ) {
2681      $t = wp_get_mime_types();
2682  
2683      unset( $t['swf'], $t['exe'] );
2684      if ( function_exists( 'current_user_can' ) ) {
2685          $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2686      }
2687  
2688      if ( empty( $unfiltered ) ) {
2689          unset( $t['htm|html'], $t['js'] );
2690      }
2691  
2692      /**
2693       * Filters list of allowed mime types and file extensions.
2694       *
2695       * @since 2.0.0
2696       *
2697       * @param array            $t    Mime types keyed by the file extension regex corresponding to
2698       *                               those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2699       *                               removed depending on '$user' capabilities.
2700       * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2701       */
2702      return apply_filters( 'upload_mimes', $t, $user );
2703  }
2704  
2705  /**
2706   * Display "Are You Sure" message to confirm the action being taken.
2707   *
2708   * If the action has the nonce explain message, then it will be displayed
2709   * along with the "Are you sure?" message.
2710   *
2711   * @since 2.0.4
2712   *
2713   * @param string $action The nonce action.
2714   */
2715  function wp_nonce_ays( $action ) {
2716      if ( 'log-out' == $action ) {
2717          $html = sprintf(
2718              /* translators: %s: site name */
2719              __( 'You are attempting to log out of %s' ),
2720              get_bloginfo( 'name' )
2721          );
2722          $html       .= '</p><p>';
2723          $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2724          $html       .= sprintf(
2725              /* translators: %s: logout URL */
2726              __( 'Do you really want to <a href="%s">log out</a>?' ),
2727              wp_logout_url( $redirect_to )
2728          );
2729      } else {
2730          $html = __( 'The link you followed has expired.' );
2731          if ( wp_get_referer() ) {
2732              $html .= '</p><p>';
2733              $html .= sprintf(
2734                  '<a href="%s">%s</a>',
2735                  esc_url( remove_query_arg( 'updated', wp_get_referer() ) ),
2736                  __( 'Please try again.' )
2737              );
2738          }
2739      }
2740  
2741      wp_die( $html, __( 'Something went wrong.' ), 403 );
2742  }
2743  
2744  /**
2745   * Kill WordPress execution and display HTML message with error message.
2746   *
2747   * This function complements the `die()` PHP function. The difference is that
2748   * HTML will be displayed to the user. It is recommended to use this function
2749   * only when the execution should not continue any further. It is not recommended
2750   * to call this function very often, and try to handle as many errors as possible
2751   * silently or more gracefully.
2752   *
2753   * As a shorthand, the desired HTTP response code may be passed as an integer to
2754   * the `$title` parameter (the default title would apply) or the `$args` parameter.
2755   *
2756   * @since 2.0.4
2757   * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
2758   *              an integer to be used as the response code.
2759   *
2760   * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
2761   *                                  and not an Ajax or XML-RPC request, the error's messages are used.
2762   *                                  Default empty.
2763   * @param string|int       $title   Optional. Error title. If `$message` is a `WP_Error` object,
2764   *                                  error data with the key 'title' may be used to specify the title.
2765   *                                  If `$title` is an integer, then it is treated as the response
2766   *                                  code. Default empty.
2767   * @param string|array|int $args {
2768   *     Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
2769   *     as the response code. Default empty array.
2770   *
2771   *     @type int    $response       The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
2772   *     @type bool   $back_link      Whether to include a link to go back. Default false.
2773   *     @type string $text_direction The text direction. This is only useful internally, when WordPress
2774   *                                  is still loading and the site's locale is not set up yet. Accepts 'rtl'.
2775   *                                  Default is the value of is_rtl().
2776   * }
2777   */
2778  function wp_die( $message = '', $title = '', $args = array() ) {
2779  
2780      if ( is_int( $args ) ) {
2781          $args = array( 'response' => $args );
2782      } elseif ( is_int( $title ) ) {
2783          $args  = array( 'response' => $title );
2784          $title = '';
2785      }
2786  
2787      if ( wp_doing_ajax() ) {
2788          /**
2789           * Filters the callback for killing WordPress execution for Ajax requests.
2790           *
2791           * @since 3.4.0
2792           *
2793           * @param callable $function Callback function name.
2794           */
2795          $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2796      } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2797          /**
2798           * Filters the callback for killing WordPress execution for XML-RPC requests.
2799           *
2800           * @since 3.4.0
2801           *
2802           * @param callable $function Callback function name.
2803           */
2804          $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2805      } else {
2806          /**
2807           * Filters the callback for killing WordPress execution for all non-Ajax, non-XML-RPC requests.
2808           *
2809           * @since 3.0.0
2810           *
2811           * @param callable $function Callback function name.
2812           */
2813          $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2814      }
2815  
2816      call_user_func( $function, $message, $title, $args );
2817  }
2818  
2819  /**
2820   * Kills WordPress execution and display HTML message with error message.
2821   *
2822   * This is the default handler for wp_die if you want a custom one for your
2823   * site then you can overload using the {@see 'wp_die_handler'} filter in wp_die().
2824   *
2825   * @since 3.0.0
2826   * @access private
2827   *
2828   * @param string|WP_Error $message Error message or WP_Error object.
2829   * @param string          $title   Optional. Error title. Default empty.
2830   * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
2831   */
2832  function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2833      $defaults = array( 'response' => 500 );
2834      $r        = wp_parse_args( $args, $defaults );
2835  
2836      $have_gettext = function_exists( '__' );
2837  
2838      if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2839          if ( empty( $title ) ) {
2840              $error_data = $message->get_error_data();
2841              if ( is_array( $error_data ) && isset( $error_data['title'] ) ) {
2842                  $title = $error_data['title'];
2843              }
2844          }
2845          $errors = $message->get_error_messages();
2846          switch ( count( $errors ) ) {
2847              case 0:
2848                  $message = '';
2849                  break;
2850              case 1:
2851                  $message = "<p>{$errors[0]}</p>";
2852                  break;
2853              default:
2854                  $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2855                  break;
2856          }
2857      } elseif ( is_string( $message ) ) {
2858          $message = "<p>$message</p>";
2859      }
2860  
2861      if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2862          $back_text = $have_gettext ? __( '&laquo; Back' ) : '&laquo; Back';
2863          $message  .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2864      }
2865  
2866      if ( ! did_action( 'admin_head' ) ) :
2867          if ( ! headers_sent() ) {
2868              status_header( $r['response'] );
2869              nocache_headers();
2870              header( 'Content-Type: text/html; charset=utf-8' );
2871          }
2872  
2873          if ( empty( $title ) ) {
2874              $title = $have_gettext ? __( 'WordPress &rsaquo; Error' ) : 'WordPress &rsaquo; Error';
2875          }
2876  
2877          $text_direction = 'ltr';
2878          if ( isset( $r['text_direction'] ) && 'rtl' == $r['text_direction'] ) {
2879              $text_direction = 'rtl';
2880          } elseif ( function_exists( 'is_rtl' ) && is_rtl() ) {
2881              $text_direction = 'rtl';
2882          }
2883  
2884          if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) {
2885              $dir_attr = get_language_attributes();
2886          } else {
2887              $dir_attr = "dir='$text_direction'";
2888          }
2889  ?>
2890  <!DOCTYPE html>
2891  <html xmlns="http://www.w3.org/1999/xhtml" <?php echo $dir_attr; ?>>
2892  <head>
2893      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2894      <meta name="viewport" content="width=device-width">
2895      <?php
2896      if ( function_exists( 'wp_no_robots' ) ) {
2897          wp_no_robots();
2898      }
2899      ?>
2900      <title><?php echo $title; ?></title>
2901      <style type="text/css">
2902          html {
2903              background: #f1f1f1;
2904          }
2905          body {
2906              background: #fff;
2907              color: #444;
2908              font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
2909              margin: 2em auto;
2910              padding: 1em 2em;
2911              max-width: 700px;
2912              -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2913              box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2914          }
2915          h1 {
2916              border-bottom: 1px solid #dadada;
2917              clear: both;
2918              color: #666;
2919              font-size: 24px;
2920              margin: 30px 0 0 0;
2921              padding: 0;
2922              padding-bottom: 7px;
2923          }
2924          #error-page {
2925              margin-top: 50px;
2926          }
2927          #error-page p {
2928              font-size: 14px;
2929              line-height: 1.5;
2930              margin: 25px 0 20px;
2931          }
2932          #error-page code {
2933              font-family: Consolas, Monaco, monospace;
2934          }
2935          ul li {
2936              margin-bottom: 10px;
2937              font-size: 14px ;
2938          }
2939          a {
2940              color: #0073aa;
2941          }
2942          a:hover,
2943          a:active {
2944              color: #00a0d2;
2945          }
2946          a:focus {
2947              color: #124964;
2948              -webkit-box-shadow:
2949                  0 0 0 1px #5b9dd9,
2950                  0 0 2px 1px rgba(30, 140, 190, .8);
2951              box-shadow:
2952                  0 0 0 1px #5b9dd9,
2953                  0 0 2px 1px rgba(30, 140, 190, .8);
2954              outline: none;
2955          }
2956          .button {
2957              background: #f7f7f7;
2958              border: 1px solid #ccc;
2959              color: #555;
2960              display: inline-block;
2961              text-decoration: none;
2962              font-size: 13px;
2963              line-height: 26px;
2964              height: 28px;
2965              margin: 0;
2966              padding: 0 10px 1px;
2967              cursor: pointer;
2968              -webkit-border-radius: 3px;
2969              -webkit-appearance: none;
2970              border-radius: 3px;
2971              white-space: nowrap;
2972              -webkit-box-sizing: border-box;
2973              -moz-box-sizing:    border-box;
2974              box-sizing:         border-box;
2975  
2976              -webkit-box-shadow: 0 1px 0 #ccc;
2977              box-shadow: 0 1px 0 #ccc;
2978               vertical-align: top;
2979          }
2980  
2981          .button.button-large {
2982              height: 30px;
2983              line-height: 28px;
2984              padding: 0 12px 2px;
2985          }
2986  
2987          .button:hover,
2988          .button:focus {
2989              background: #fafafa;
2990              border-color: #999;
2991              color: #23282d;
2992          }
2993  
2994          .button:focus  {
2995              border-color: #5b9dd9;
2996              -webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
2997              box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
2998              outline: none;
2999          }
3000  
3001          .button:active {
3002              background: #eee;
3003              border-color: #999;
3004               -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
3005               box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
3006               -webkit-transform: translateY(1px);
3007               -ms-transform: translateY(1px);
3008               transform: translateY(1px);
3009          }
3010  
3011          <?php
3012          if ( 'rtl' == $text_direction ) {
3013              echo 'body { font-family: Tahoma, Arial; }';
3014          }
3015          ?>
3016      </style>
3017  </head>
3018  <body id="error-page">
3019  <?php endif; // ! did_action( 'admin_head' ) ?>
3020      <?php echo $message; ?>
3021  </body>
3022  </html>
3023  <?php
3024      die();
3025  }
3026  
3027  /**
3028   * Kill WordPress execution and display XML message with error message.
3029   *
3030   * This is the handler for wp_die when processing XMLRPC requests.
3031   *
3032   * @since 3.2.0
3033   * @access private
3034   *
3035   * @global wp_xmlrpc_server $wp_xmlrpc_server
3036   *
3037   * @param string       $message Error message.
3038   * @param string       $title   Optional. Error title. Default empty.
3039   * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
3040   */
3041  function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
3042      global $wp_xmlrpc_server;
3043      $defaults = array( 'response' => 500 );
3044  
3045      $r = wp_parse_args( $args, $defaults );
3046  
3047      if ( $wp_xmlrpc_server ) {
3048          $error = new IXR_Error( $r['response'], $message );
3049          $wp_xmlrpc_server->output( $error->getXml() );
3050      }
3051      die();
3052  }
3053  
3054  /**
3055   * Kill WordPress ajax execution.
3056   *
3057   * This is the handler for wp_die when processing Ajax requests.
3058   *
3059   * @since 3.4.0
3060   * @access private
3061   *
3062   * @param string       $message Error message.
3063   * @param string       $title   Optional. Error title (unused). Default empty.
3064   * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
3065   */
3066  function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
3067      $defaults = array(
3068          'response' => 200,
3069      );
3070      $r        = wp_parse_args( $args, $defaults );
3071  
3072      if ( ! headers_sent() && null !== $r['response'] ) {
3073          status_header( $r['response'] );
3074      }
3075  
3076      if ( is_scalar( $message ) ) {
3077          die( (string) $message );
3078      }
3079      die( '0' );
3080  }
3081  
3082  /**
3083   * Kill WordPress execution.
3084   *
3085   * This is the handler for wp_die when processing APP requests.
3086   *
3087   * @since 3.4.0
3088   * @access private
3089   *
3090   * @param string $message Optional. Response to print. Default empty.
3091   */
3092  function _scalar_wp_die_handler( $message = '' ) {
3093      if ( is_scalar( $message ) ) {
3094          die( (string) $message );
3095      }
3096      die();
3097  }
3098  
3099  /**
3100   * Encode a variable into JSON, with some sanity checks.
3101   *
3102   * @since 4.1.0
3103   *
3104   * @param mixed $data    Variable (usually an array or object) to encode as JSON.
3105   * @param int   $options Optional. Options to be passed to json_encode(). Default 0.
3106   * @param int   $depth   Optional. Maximum depth to walk through $data. Must be
3107   *                       greater than 0. Default 512.
3108   * @return string|false The JSON encoded string, or false if it cannot be encoded.
3109   */
3110  function wp_json_encode( $data, $options = 0, $depth = 512 ) {
3111      /*
3112       * json_encode() has had extra params added over the years.
3113       * $options was added in 5.3, and $depth in 5.5.
3114       * We need to make sure we call it with the correct arguments.
3115       */
3116      if ( version_compare( PHP_VERSION, '5.5', '>=' ) ) {
3117          $args = array( $data, $options, $depth );
3118      } elseif ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
3119          $args = array( $data, $options );
3120      } else {
3121          $args = array( $data );
3122      }
3123  
3124      // Prepare the data for JSON serialization.
3125      $args[0] = _wp_json_prepare_data( $data );
3126  
3127      $json = @call_user_func_array( 'json_encode', $args );
3128  
3129      // If json_encode() was successful, no need to do more sanity checking.
3130      // ... unless we're in an old version of PHP, and json_encode() returned
3131      // a string containing 'null'. Then we need to do more sanity checking.
3132      if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) ) {
3133          return $json;
3134      }
3135  
3136      try {
3137          $args[0] = _wp_json_sanity_check( $data, $depth );
3138      } catch ( Exception $e ) {
3139          return false;
3140      }
3141  
3142      return call_user_func_array( 'json_encode', $args );
3143  }
3144  
3145  /**
3146   * Perform sanity checks on data that shall be encoded to JSON.
3147   *
3148   * @ignore
3149   * @since 4.1.0
3150   * @access private
3151   *
3152   * @see wp_json_encode()
3153   *
3154   * @param mixed $data  Variable (usually an array or object) to encode as JSON.
3155   * @param int   $depth Maximum depth to walk through $data. Must be greater than 0.
3156   * @return mixed The sanitized data that shall be encoded to JSON.
3157   */
3158  function _wp_json_sanity_check( $data, $depth ) {
3159      if ( $depth < 0 ) {
3160          throw new Exception( 'Reached depth limit' );
3161      }
3162  
3163      if ( is_array( $data ) ) {
3164          $output = array();
3165          foreach ( $data as $id => $el ) {
3166              // Don't forget to sanitize the ID!
3167              if ( is_string( $id ) ) {
3168                  $clean_id = _wp_json_convert_string( $id );
3169              } else {
3170                  $clean_id = $id;
3171              }
3172  
3173              // Check the element type, so that we're only recursing if we really have to.
3174              if ( is_array( $el ) || is_object( $el ) ) {
3175                  $output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
3176              } elseif ( is_string( $el ) ) {
3177                  $output[ $clean_id ] = _wp_json_convert_string( $el );
3178              } else {
3179                  $output[ $clean_id ] = $el;
3180              }
3181          }
3182      } elseif ( is_object( $data ) ) {
3183          $output = new stdClass;
3184          foreach ( $data as $id => $el ) {
3185              if ( is_string( $id ) ) {
3186                  $clean_id = _wp_json_convert_string( $id );
3187              } else {
3188                  $clean_id = $id;
3189              }
3190  
3191              if ( is_array( $el ) || is_object( $el ) ) {
3192                  $output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
3193              } elseif ( is_string( $el ) ) {
3194                  $output->$clean_id = _wp_json_convert_string( $el );
3195              } else {
3196                  $output->$clean_id = $el;
3197              }
3198          }
3199      } elseif ( is_string( $data ) ) {
3200          return _wp_json_convert_string( $data );
3201      } else {
3202          return $data;
3203      }
3204  
3205      return $output;
3206  }
3207  
3208  /**
3209   * Convert a string to UTF-8, so that it can be safely encoded to JSON.
3210   *
3211   * @ignore
3212   * @since 4.1.0
3213   * @access private
3214   *
3215   * @see _wp_json_sanity_check()
3216   *
3217   * @staticvar bool $use_mb
3218   *
3219   * @param string $string The string which is to be converted.
3220   * @return string The checked string.
3221   */
3222  function _wp_json_convert_string( $string ) {
3223      static $use_mb = null;
3224      if ( is_null( $use_mb ) ) {
3225          $use_mb = function_exists( 'mb_convert_encoding' );
3226      }
3227  
3228      if ( $use_mb ) {
3229          $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
3230          if ( $encoding ) {
3231              return mb_convert_encoding( $string, 'UTF-8', $encoding );
3232          } else {
3233              return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
3234          }
3235      } else {
3236          return wp_check_invalid_utf8( $string, true );
3237      }
3238  }
3239  
3240  /**
3241   * Prepares response data to be serialized to JSON.
3242   *
3243   * This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
3244   *
3245   * @ignore
3246   * @since 4.4.0
3247   * @access private
3248   *
3249   * @param mixed $data Native representation.
3250   * @return bool|int|float|null|string|array Data ready for `json_encode()`.
3251   */
3252  function _wp_json_prepare_data( $data ) {
3253      if ( ! defined( 'WP_JSON_SERIALIZE_COMPATIBLE' ) || WP_JSON_SERIALIZE_COMPATIBLE === false ) {
3254          return $data;
3255      }
3256  
3257      switch ( gettype( $data ) ) {
3258          case 'boolean':
3259          case 'integer':
3260          case 'double':
3261          case 'string':
3262          case 'NULL':
3263              // These values can be passed through.
3264              return $data;
3265  
3266          case 'array':
3267              // Arrays must be mapped in case they also return objects.
3268              return array_map( '_wp_json_prepare_data', $data );
3269  
3270          case 'object':
3271              // If this is an incomplete object (__PHP_Incomplete_Class), bail.
3272              if ( ! is_object( $data ) ) {
3273                  return null;
3274              }
3275  
3276              if ( $data instanceof JsonSerializable ) {
3277                  $data = $data->jsonSerialize();
3278              } else {
3279                  $data = get_object_vars( $data );
3280              }
3281  
3282              // Now, pass the array (or whatever was returned from jsonSerialize through).
3283              return _wp_json_prepare_data( $data );
3284  
3285          default:
3286              return null;
3287      }
3288  }
3289  
3290  /**
3291   * Send a JSON response back to an Ajax request.
3292   *
3293   * @since 3.5.0
3294   * @since 4.7.0 The `$status_code` parameter was added.
3295   *
3296   * @param mixed $response    Variable (usually an array or object) to encode as JSON,
3297   *                           then print and die.
3298   * @param int   $status_code The HTTP status code to output.
3299   */
3300  function wp_send_json( $response, $status_code = null ) {
3301      @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
3302      if ( null !== $status_code ) {
3303          status_header( $status_code );
3304      }
3305      echo wp_json_encode( $response );
3306  
3307      if ( wp_doing_ajax() ) {
3308          wp_die(
3309              '', '', array(
3310                  'response' => null,
3311              )
3312          );
3313      } else {
3314          die;
3315      }
3316  }
3317  
3318  /**
3319   * Send a JSON response back to an Ajax request, indicating success.
3320   *
3321   * @since 3.5.0
3322   * @since 4.7.0 The `$status_code` parameter was added.
3323   *
3324   * @param mixed $data        Data to encode as JSON, then print and die.
3325   * @param int   $status_code The HTTP status code to output.
3326   */
3327  function wp_send_json_success( $data = null, $status_code = null ) {
3328      $response = array( 'success' => true );
3329  
3330      if ( isset( $data ) ) {
3331          $response['data'] = $data;
3332      }
3333  
3334      wp_send_json( $response, $status_code );
3335  }
3336  
3337  /**
3338   * Send a JSON response back to an Ajax request, indicating failure.
3339   *
3340   * If the `$data` parameter is a WP_Error object, the errors
3341   * within the object are processed and output as an array of error
3342   * codes and corresponding messages. All other types are output
3343   * without further processing.
3344   *
3345   * @since 3.5.0
3346   * @since 4.1.0 The `$data` parameter is now processed if a WP_Error object is passed in.
3347   * @since 4.7.0 The `$status_code` parameter was added.
3348   *
3349   * @param mixed $data        Data to encode as JSON, then print and die.
3350   * @param int   $status_code The HTTP status code to output.
3351   */
3352  function wp_send_json_error( $data = null, $status_code = null ) {
3353      $response = array( 'success' => false );
3354  
3355      if ( isset( $data ) ) {
3356          if ( is_wp_error( $data ) ) {
3357              $result = array();
3358              foreach ( $data->errors as $code => $messages ) {
3359                  foreach ( $messages as $message ) {
3360                      $result[] = array(
3361                          'code'    => $code,
3362                          'message' => $message,
3363                      );
3364                  }
3365              }
3366  
3367              $response['data'] = $result;
3368          } else {
3369              $response['data'] = $data;
3370          }
3371      }
3372  
3373      wp_send_json( $response, $status_code );
3374  }
3375  
3376  /**
3377   * Checks that a JSONP callback is a valid JavaScript callback.
3378   *
3379   * Only allows alphanumeric characters and the dot character in callback
3380   * function names. This helps to mitigate XSS attacks caused by directly
3381   * outputting user input.
3382   *
3383   * @since 4.6.0
3384   *
3385   * @param string $callback Supplied JSONP callback function.
3386   * @return bool True if valid callback, otherwise false.
3387   */
3388  function wp_check_jsonp_callback( $callback ) {
3389      if ( ! is_string( $callback ) ) {
3390          return false;
3391      }
3392  
3393      preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
3394  
3395      return 0 === $illegal_char_count;
3396  }
3397  
3398  /**
3399   * Retrieve the WordPress home page URL.
3400   *
3401   * If the constant named 'WP_HOME' exists, then it will be used and returned
3402   * by the function. This can be used to counter the redirection on your local
3403   * development environment.
3404   *
3405   * @since 2.2.0
3406   * @access private
3407   *
3408   * @see WP_HOME
3409   *
3410   * @param string $url URL for the home location.
3411   * @return string Homepage location.
3412   */
3413  function _config_wp_home( $url = '' ) {
3414      if ( defined( 'WP_HOME' ) ) {
3415          return untrailingslashit( WP_HOME );
3416      }
3417      return $url;
3418  }
3419  
3420  /**
3421   * Retrieve the WordPress site URL.
3422   *
3423   * If the constant named 'WP_SITEURL' is defined, then the value in that
3424   * constant will always be returned. This can be used for debugging a site
3425   * on your localhost while not having to change the database to your URL.
3426   *
3427   * @since 2.2.0
3428   * @access private
3429   *
3430   * @see WP_SITEURL
3431   *
3432   * @param string $url URL to set the WordPress site location.
3433   * @return string The WordPress Site URL.
3434   */
3435  function _config_wp_siteurl( $url = '' ) {
3436      if ( defined( 'WP_SITEURL' ) ) {
3437          return untrailingslashit( WP_SITEURL );
3438      }
3439      return $url;
3440  }
3441  
3442  /**
3443   * Delete the fresh site option.
3444   *
3445   * @since 4.7.0
3446   * @access private
3447   */
3448  function _delete_option_fresh_site() {
3449      update_option( 'fresh_site', '0' );
3450  }
3451  
3452  /**
3453   * Set the localized direction for MCE plugin.
3454   *
3455   * Will only set the direction to 'rtl', if the WordPress locale has
3456   * the text direction set to 'rtl'.
3457   *
3458   * Fills in the 'directionality' setting, enables the 'directionality'
3459   * plugin, and adds the 'ltr' button to 'toolbar1', formerly
3460   * 'theme_advanced_buttons1' array keys. These keys are then returned
3461   * in the $mce_init (TinyMCE settings) array.
3462   *
3463   * @since 2.1.0
3464   * @access private
3465   *
3466   * @param array $mce_init MCE settings array.
3467   * @return array Direction set for 'rtl', if needed by locale.
3468   */
3469  function _mce_set_direction( $mce_init ) {
3470      if ( is_rtl() ) {
3471          $mce_init['directionality'] = 'rtl';
3472          $mce_init['rtl_ui']         = true;
3473  
3474          if ( ! empty( $mce_init['plugins'] ) && strpos( $mce_init['plugins'], 'directionality' ) === false ) {
3475              $mce_init['plugins'] .= ',directionality';
3476          }
3477  
3478          if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match( '/\bltr\b/', $mce_init['toolbar1'] ) ) {
3479              $mce_init['toolbar1'] .= ',ltr';
3480          }
3481      }
3482  
3483      return $mce_init;
3484  }
3485  
3486  
3487  /**
3488   * Convert smiley code to the icon graphic file equivalent.
3489   *
3490   * You can turn off smilies, by going to the write setting screen and unchecking
3491   * the box, or by setting 'use_smilies' option to false or removing the option.
3492   *
3493   * Plugins may override the default smiley list by setting the $wpsmiliestrans
3494   * to an array, with the key the code the blogger types in and the value the
3495   * image file.
3496   *
3497   * The $wp_smiliessearch global is for the regular expression and is set each
3498   * time the function is called.
3499   *
3500   * The full list of smilies can be found in the function and won't be listed in
3501   * the description. Probably should create a Codex page for it, so that it is
3502   * available.
3503   *
3504   * @global array $wpsmiliestrans
3505   * @global array $wp_smiliessearch
3506   *
3507   * @since 2.2.0
3508   */
3509  function smilies_init() {
3510      global $wpsmiliestrans, $wp_smiliessearch;
3511  
3512      // don't bother setting up smilies if they are disabled
3513      if ( ! get_option( 'use_smilies' ) ) {
3514          return;
3515      }
3516  
3517      if ( ! isset( $wpsmiliestrans ) ) {
3518          $wpsmiliestrans = array(
3519              ':mrgreen:' => 'mrgreen.png',
3520              ':neutral:' => "\xf0\x9f\x98\x90",
3521              ':twisted:' => "\xf0\x9f\x98\x88",
3522              ':arrow:'   => "\xe2\x9e\xa1",
3523              ':shock:'   => "\xf0\x9f\x98\xaf",
3524              ':smile:'   => "\xf0\x9f\x99\x82",
3525              ':???:'     => "\xf0\x9f\x98\x95",
3526              ':cool:'    => "\xf0\x9f\x98\x8e",
3527              ':evil:'    => "\xf0\x9f\x91\xbf",
3528              ':grin:'    => "\xf0\x9f\x98\x80",
3529              ':idea:'    => "\xf0\x9f\x92\xa1",
3530              ':oops:'    => "\xf0\x9f\x98\xb3",
3531              ':razz:'    => "\xf0\x9f\x98\x9b",
3532              ':roll:'    => "\xf0\x9f\x99\x84",
3533              ':wink:'    => "\xf0\x9f\x98\x89",
3534              ':cry:'     => "\xf0\x9f\x98\xa5",
3535              ':eek:'     => "\xf0\x9f\x98\xae",
3536              ':lol:'     => "\xf0\x9f\x98\x86",
3537              ':mad:'     => "\xf0\x9f\x98\xa1",
3538              ':sad:'     => "\xf0\x9f\x99\x81",
3539              '8-)'       => "\xf0\x9f\x98\x8e",
3540              '8-O'       => "\xf0\x9f\x98\xaf",
3541              ':-('       => "\xf0\x9f\x99\x81",
3542              ':-)'       => "\xf0\x9f\x99\x82",
3543              ':-?'       => "\xf0\x9f\x98\x95",
3544              ':-D'       => "\xf0\x9f\x98\x80",
3545              ':-P'       => "\xf0\x9f\x98\x9b",
3546              ':-o'       => "\xf0\x9f\x98\xae",
3547              ':-x'       => "\xf0\x9f\x98\xa1",
3548              ':-|'       => "\xf0\x9f\x98\x90",
3549              ';-)'       => "\xf0\x9f\x98\x89",
3550              // This one transformation breaks regular text with frequency.
3551              //     '8)' => "\xf0\x9f\x98\x8e",
3552              '8O'        => "\xf0\x9f\x98\xaf",
3553              ':('        => "\xf0\x9f\x99\x81",
3554              ':)'        => "\xf0\x9f\x99\x82",
3555              ':?'        => "\xf0\x9f\x98\x95",
3556              ':D'        => "\xf0\x9f\x98\x80",
3557              ':P'        => "\xf0\x9f\x98\x9b",
3558              ':o'        => "\xf0\x9f\x98\xae",
3559              ':x'        => "\xf0\x9f\x98\xa1",
3560              ':|'        => "\xf0\x9f\x98\x90",
3561              ';)'        => "\xf0\x9f\x98\x89",
3562              ':!:'       => "\xe2\x9d\x97",
3563              ':?:'       => "\xe2\x9d\x93",
3564          );
3565      }
3566  
3567      /**
3568       * Filters all the smilies.
3569       *
3570       * This filter must be added before `smilies_init` is run, as
3571       * it is normally only run once to setup the smilies regex.
3572       *
3573       * @since 4.7.0
3574       *
3575       * @param array $wpsmiliestrans List of the smilies.
3576       */
3577      $wpsmiliestrans = apply_filters( 'smilies', $wpsmiliestrans );
3578  
3579      if ( count( $wpsmiliestrans ) == 0 ) {
3580          return;
3581      }
3582  
3583      /*
3584       * NOTE: we sort the smilies in reverse key order. This is to make sure
3585       * we match the longest possible smilie (:???: vs :?) as the regular
3586       * expression used below is first-match
3587       */
3588      krsort( $wpsmiliestrans );
3589  
3590      $spaces = wp_spaces_regexp();
3591  
3592      // Begin first "subpattern"
3593      $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
3594  
3595      $subchar = '';
3596      foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
3597          $firstchar = substr( $smiley, 0, 1 );
3598          $rest      = substr( $smiley, 1 );
3599  
3600          // new subpattern?
3601          if ( $firstchar != $subchar ) {
3602              if ( $subchar != '' ) {
3603                  $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
3604                  $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
3605              }
3606              $subchar           = $firstchar;
3607              $wp_smiliessearch .= preg_quote( $firstchar, '/' ) . '(?:';
3608          } else {
3609              $wp_smiliessearch .= '|';
3610          }
3611          $wp_smiliessearch .= preg_quote( $rest, '/' );
3612      }
3613  
3614      $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
3615  
3616  }
3617  
3618  /**
3619   * Merge user defined arguments into defaults array.
3620   *
3621   * This function is used throughout WordPress to allow for both string or array
3622   * to be merged into another array.
3623   *
3624   * @since 2.2.0
3625   * @since 2.3.0 `$args` can now also be an object.
3626   *
3627   * @param string|array|object $args     Value to merge with $defaults.
3628   * @param array               $defaults Optional. Array that serves as the defaults. Default empty.
3629   * @return array Merged user defined values with defaults.
3630   */
3631  function wp_parse_args( $args, $defaults = '' ) {
3632      if ( is_object( $args ) ) {
3633          $r = get_object_vars( $args );
3634      } elseif ( is_array( $args ) ) {
3635          $r =& $args;
3636      } else {
3637          wp_parse_str( $args, $r );
3638      }
3639  
3640      if ( is_array( $defaults ) ) {
3641          return array_merge( $defaults, $r );
3642      }
3643      return $r;
3644  }
3645  
3646  /**
3647   * Clean up an array, comma- or space-separated list of IDs.
3648   *
3649   * @since 3.0.0
3650   *
3651   * @param array|string $list List of ids.
3652   * @return array Sanitized array of IDs.
3653   */
3654  function wp_parse_id_list( $list ) {
3655      if ( ! is_array( $list ) ) {
3656          $list = preg_split( '/[\s,]+/', $list );
3657      }
3658  
3659      return array_unique( array_map( 'absint', $list ) );
3660  }
3661  
3662  /**
3663   * Clean up an array, comma- or space-separated list of slugs.
3664   *
3665   * @since 4.7.0
3666   *
3667   * @param  array|string $list List of slugs.
3668   * @return array Sanitized array of slugs.
3669   */
3670  function wp_parse_slug_list( $list ) {
3671      if ( ! is_array( $list ) ) {
3672          $list = preg_split( '/[\s,]+/', $list );
3673      }
3674  
3675      foreach ( $list as $key => $value ) {
3676          $list[ $key ] = sanitize_title( $value );
3677      }
3678  
3679      return array_unique( $list );
3680  }
3681  
3682  /**
3683   * Extract a slice of an array, given a list of keys.
3684   *
3685   * @since 3.1.0
3686   *
3687   * @param array $array The original array.
3688   * @param array $keys  The list of keys.
3689   * @return array The array slice.
3690   */
3691  function wp_array_slice_assoc( $array, $keys ) {
3692      $slice = array();
3693      foreach ( $keys as $key ) {
3694          if ( isset( $array[ $key ] ) ) {
3695              $slice[ $key ] = $array[ $key ];
3696          }
3697      }
3698  
3699      return $slice;
3700  }
3701  
3702  /**
3703   * Determines if the variable is a numeric-indexed array.
3704   *
3705   * @since 4.4.0
3706   *
3707   * @param mixed $data Variable to check.
3708   * @return bool Whether the variable is a list.
3709   */
3710  function wp_is_numeric_array( $data ) {
3711      if ( ! is_array( $data ) ) {
3712          return false;
3713      }
3714  
3715      $keys        = array_keys( $data );
3716      $string_keys = array_filter( $keys, 'is_string' );
3717      return count( $string_keys ) === 0;
3718  }
3719  
3720  /**
3721   * Filters a list of objects, based on a set of key => value arguments.
3722   *
3723   * @since 3.0.0
3724   * @since 4.7.0 Uses `WP_List_Util` class.
3725   *
3726   * @param array       $list     An array of objects to filter
3727   * @param array       $args     Optional. An array of key => value arguments to match
3728   *                              against each object. Default empty array.
3729   * @param string      $operator Optional. The logical operation to perform. 'or' means
3730   *                              only one element from the array needs to match; 'and'
3731   *                              means all elements must match; 'not' means no elements may
3732   *                              match. Default 'and'.
3733   * @param bool|string $field    A field from the object to place instead of the entire object.
3734   *                              Default false.
3735   * @return array A list of objects or object fields.
3736   */
3737  function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
3738      if ( ! is_array( $list ) ) {
3739          return array();
3740      }
3741  
3742      $util = new WP_List_Util( $list );
3743  
3744      $util->filter( $args, $operator );
3745  
3746      if ( $field ) {
3747          $util->pluck( $field );
3748      }
3749  
3750      return $util->get_output();
3751  }
3752  
3753  /**
3754   * Filters a list of objects, based on a set of key => value arguments.
3755   *
3756   * @since 3.1.0
3757   * @since 4.7.0 Uses `WP_List_Util` class.
3758   *
3759   * @param array  $list     An array of objects to filter.
3760   * @param array  $args     Optional. An array of key => value arguments to match
3761   *                         against each object. Default empty array.
3762   * @param string $operator Optional. The logical operation to perform. 'AND' means
3763   *                         all elements from the array must match. 'OR' means only
3764   *                         one element needs to match. 'NOT' means no elements may
3765   *                         match. Default 'AND'.
3766   * @return array Array of found values.
3767   */
3768  function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
3769      if ( ! is_array( $list ) ) {
3770          return array();
3771      }
3772  
3773      $util = new WP_List_Util( $list );
3774      return $util->filter( $args, $operator );
3775  }
3776  
3777  /**
3778   * Pluck a certain field out of each object in a list.
3779   *
3780   * This has the same functionality and prototype of
3781   * array_column() (PHP 5.5) but also supports objects.
3782   *
3783   * @since 3.1.0
3784   * @since 4.0.0 $index_key parameter added.
3785   * @since 4.7.0 Uses `WP_List_Util` class.
3786   *
3787   * @param array      $list      List of objects or arrays
3788   * @param int|string $field     Field from the object to place instead of the entire object
3789   * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
3790   *                              Default null.
3791   * @return array Array of found values. If `$index_key` is set, an array of found values with keys
3792   *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
3793   *               `$list` will be preserved in the results.
3794   */
3795  function wp_list_pluck( $list, $field, $index_key = null ) {
3796      $util = new WP_List_Util( $list );
3797      return $util->pluck( $field, $index_key );
3798  }
3799  
3800  /**
3801   * Sorts a list of objects, based on one or more orderby arguments.
3802   *
3803   * @since 4.7.0
3804   *
3805   * @param array        $list          An array of objects to filter.
3806   * @param string|array $orderby       Optional. Either the field name to order by or an array
3807   *                                    of multiple orderby fields as $orderby => $order.
3808   * @param string       $order         Optional. Either 'ASC' or 'DESC'. Only used if $orderby
3809   *                                    is a string.
3810   * @param bool         $preserve_keys Optional. Whether to preserve keys. Default false.
3811   * @return array The sorted array.
3812   */
3813  function wp_list_sort( $list, $orderby = array(), $order = 'ASC', $preserve_keys = false ) {
3814      if ( ! is_array( $list ) ) {
3815          return array();
3816      }
3817  
3818      $util = new WP_List_Util( $list );
3819      return $util->sort( $orderby, $order, $preserve_keys );
3820  }
3821  
3822  /**
3823   * Determines if Widgets library should be loaded.
3824   *
3825   * Checks to make sure that the widgets library hasn't already been loaded.
3826   * If it hasn't, then it will load the widgets library and run an action hook.
3827   *
3828   * @since 2.2.0
3829   */
3830  function wp_maybe_load_widgets() {
3831      /**
3832       * Filters whether to load the Widgets library.
3833       *
3834       * Passing a falsey value to the filter will effectively short-circuit
3835       * the Widgets library from loading.
3836       *
3837       * @since 2.8.0
3838       *
3839       * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
3840       *                                    Default true.
3841       */
3842      if ( ! apply_filters( 'load_default_widgets', true ) ) {
3843          return;
3844      }
3845  
3846      require_once ( ABSPATH . WPINC . '/default-widgets.php' );
3847  
3848      add_action( '_admin_menu', 'wp_widgets_add_menu' );
3849  }
3850  
3851  /**
3852   * Append the Widgets menu to the themes main menu.
3853   *
3854   * @since 2.2.0
3855   *
3856   * @global array $submenu
3857   */
3858  function wp_widgets_add_menu() {
3859      global $submenu;
3860  
3861      if ( ! current_theme_supports( 'widgets' ) ) {
3862          return;
3863      }
3864  
3865      $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
3866      ksort( $submenu['themes.php'], SORT_NUMERIC );
3867  }
3868  
3869  /**
3870   * Flush all output buffers for PHP 5.2.
3871   *
3872   * Make sure all output buffers are flushed before our singletons are destroyed.
3873   *
3874   * @since 2.2.0
3875   */
3876  function wp_ob_end_flush_all() {
3877      $levels = ob_get_level();
3878      for ( $i = 0; $i < $levels; $i++ ) {
3879          ob_end_flush();
3880      }
3881  }
3882  
3883  /**
3884   * Load custom DB error or display WordPress DB error.
3885   *
3886   * If a file exists in the wp-content directory named db-error.php, then it will
3887   * be loaded instead of displaying the WordPress DB error. If it is not found,
3888   * then the WordPress DB error will be displayed instead.
3889   *
3890   * The WordPress DB error sets the HTTP status header to 500 to try to prevent
3891   * search engines from caching the message. Custom DB messages should do the
3892   * same.
3893   *
3894   * This function was backported to WordPress 2.3.2, but originally was added
3895   * in WordPress 2.5.0.
3896   *
3897   * @since 2.3.2
3898   *
3899   * @global wpdb $wpdb WordPress database abstraction object.
3900   */
3901  function dead_db() {
3902      global $wpdb;
3903  
3904      wp_load_translations_early();
3905  
3906      // Load custom DB error template, if present.
3907      if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
3908          require_once( WP_CONTENT_DIR . '/db-error.php' );
3909          die();
3910      }
3911  
3912      // If installing or in the admin, provide the verbose message.
3913      if ( wp_installing() || defined( 'WP_ADMIN' ) ) {
3914          wp_die( $wpdb->error );
3915      }
3916  
3917      // Otherwise, be terse.
3918      status_header( 500 );
3919      nocache_headers();
3920      header( 'Content-Type: text/html; charset=utf-8' );
3921  
3922      $dir_attr = '';
3923      if ( is_rtl() ) {
3924          $dir_attr = ' dir="rtl"';
3925      }
3926  ?>
3927  <!DOCTYPE html>
3928  <html xmlns="http://www.w3.org/1999/xhtml"<?php echo $dir_attr; ?>>
3929  <head>
3930  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3931      <title><?php _e( 'Database Error' ); ?></title>
3932  
3933  </head>
3934  <body>
3935      <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
3936  </body>
3937  </html>
3938  <?php
3939      die();
3940  }
3941  
3942  /**
3943   * Convert a value to non-negative integer.
3944   *
3945   * @since 2.5.0
3946   *
3947   * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
3948   * @return int A non-negative integer.
3949   */
3950  function absint( $maybeint ) {
3951      return abs( intval( $maybeint ) );
3952  }
3953  
3954  /**
3955   * Mark a function as deprecated and inform when it has been used.
3956   *
3957   * There is a {@see 'hook deprecated_function_run'} that will be called that can be used
3958   * to get the backtrace up to what file and function called the deprecated
3959   * function.
3960   *
3961   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
3962   *
3963   * This function is to be used in every function that is deprecated.
3964   *
3965   * @since 2.5.0
3966   * @access private
3967   *
3968   * @param string $function    The function that was called.
3969   * @param string $version     The version of WordPress that deprecated the function.
3970   * @param string $replacement Optional. The function that should have been called. Default null.
3971   */
3972  function _deprecated_function( $function, $version, $replacement = null ) {
3973  
3974      /**
3975       * Fires when a deprecated function is called.
3976       *
3977       * @since 2.5.0
3978       *
3979       * @param string $function    The function that was called.
3980       * @param string $replacement The function that should have been called.
3981       * @param string $version     The version of WordPress that deprecated the function.
3982       */
3983      do_action( 'deprecated_function_run', $function, $replacement, $version );
3984  
3985      /**
3986       * Filters whether to trigger an error for deprecated functions.
3987       *
3988       * @since 2.5.0
3989       *
3990       * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3991       */
3992      if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3993          if ( function_exists( '__' ) ) {
3994              if ( ! is_null( $replacement ) ) {
3995                  /* translators: 1: PHP function name, 2: version number, 3: alternative function name */
3996                  trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $function, $version, $replacement ) );
3997              } else {
3998                  /* translators: 1: PHP function name, 2: version number */
3999                  trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $function, $version ) );
4000              }
4001          } else {
4002              if ( ! is_null( $replacement ) ) {
4003                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
4004              } else {
4005                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
4006              }
4007          }
4008      }
4009  }
4010  
4011  /**
4012   * Marks a constructor as deprecated and informs when it has been used.
4013   *
4014   * Similar to _deprecated_function(), but with different strings. Used to
4015   * remove PHP4 style constructors.
4016   *
4017   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
4018   *
4019   * This function is to be used in every PHP4 style constructor method that is deprecated.
4020   *
4021   * @since 4.3.0
4022   * @since 4.5.0 Added the `$parent_class` parameter.
4023   *
4024   * @access private
4025   *
4026   * @param string $class        The class containing the deprecated constructor.
4027   * @param string $version      The version of WordPress that deprecated the function.
4028   * @param string $parent_class Optional. The parent class calling the deprecated constructor.
4029   *                             Default empty string.
4030   */
4031  function _deprecated_constructor( $class, $version, $parent_class = '' ) {
4032  
4033      /**
4034       * Fires when a deprecated constructor is called.
4035       *
4036       * @since 4.3.0
4037       * @since 4.5.0 Added the `$parent_class` parameter.
4038       *
4039       * @param string $class        The class containing the deprecated constructor.
4040       * @param string $version      The version of WordPress that deprecated the function.
4041       * @param string $parent_class The parent class calling the deprecated constructor.
4042       */
4043      do_action( 'deprecated_constructor_run', $class, $version, $parent_class );
4044  
4045      /**
4046       * Filters whether to trigger an error for deprecated functions.
4047       *
4048       * `WP_DEBUG` must be true in addition to the filter evaluating to true.
4049       *
4050       * @since 4.3.0
4051       *
4052       * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
4053       */
4054      if ( WP_DEBUG && apply_filters( 'deprecated_constructor_trigger_error', true ) ) {
4055          if ( function_exists( '__' ) ) {
4056              if ( ! empty( $parent_class ) ) {
4057                  /* translators: 1: PHP class name, 2: PHP parent class name, 3: version number, 4: __construct() method */
4058                  trigger_error(
4059                      sprintf(
4060                          __( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
4061                          $class, $parent_class, $version, '<pre>__construct()</pre>'
4062                      )
4063                  );
4064              } else {
4065                  /* translators: 1: PHP class name, 2: version number, 3: __construct() method */
4066                  trigger_error(
4067                      sprintf(
4068                          __( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
4069                          $class, $version, '<pre>__construct()</pre>'
4070                      )
4071                  );
4072              }
4073          } else {
4074              if ( ! empty( $parent_class ) ) {
4075                  trigger_error(
4076                      sprintf(
4077                          'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
4078                          $class, $parent_class, $version, '<pre>__construct()</pre>'
4079                      )
4080                  );
4081              } else {
4082                  trigger_error(
4083                      sprintf(
4084                          'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
4085                          $class, $version, '<pre>__construct()</pre>'
4086                      )
4087                  );
4088              }
4089          }
4090      }
4091  
4092  }
4093  
4094  /**
4095   * Mark a file as deprecated and inform when it has been used.
4096   *
4097   * There is a hook {@see 'deprecated_file_included'} that will be called that can be used
4098   * to get the backtrace up to what file and function included the deprecated
4099   * file.
4100   *
4101   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
4102   *
4103   * This function is to be used in every file that is deprecated.
4104   *
4105   * @since 2.5.0
4106   * @access private
4107   *
4108   * @param string $file        The file that was included.
4109   * @param string $version     The version of WordPress that deprecated the file.
4110   * @param string $replacement Optional. The file that should have been included based on ABSPATH.
4111   *                            Default null.
4112   * @param string $message     Optional. A message regarding the change. Default empty.
4113   */
4114  function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
4115  
4116      /**
4117       * Fires when a deprecated file is called.
4118       *
4119       * @since 2.5.0
4120       *
4121       * @param string $file        The file that was called.
4122       * @param string $replacement The file that should have been included based on ABSPATH.
4123       * @param string $version     The version of WordPress that deprecated the file.
4124       * @param string $message     A message regarding the change.
4125       */
4126      do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
4127  
4128      /**
4129       * Filters whether to trigger an error for deprecated files.
4130       *
4131       * @since 2.5.0
4132       *
4133       * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
4134       */
4135      if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
4136          $message = empty( $message ) ? '' : ' ' . $message;
4137          if ( function_exists( '__' ) ) {
4138              if ( ! is_null( $replacement ) ) {
4139                  /* translators: 1: PHP file name, 2: version number, 3: alternative file name */
4140                  trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $file, $version, $replacement ) . $message );
4141              } else {
4142                  /* translators: 1: PHP file name, 2: version number */
4143                  trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $file, $version ) . $message );
4144              }
4145          } else {
4146              if ( ! is_null( $replacement ) ) {
4147                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
4148              } else {
4149                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
4150              }
4151          }
4152      }
4153  }
4154  /**
4155   * Mark a function argument as deprecated and inform when it has been used.
4156   *
4157   * This function is to be used whenever a deprecated function argument is used.
4158   * Before this function is called, the argument must be checked for whether it was
4159   * used by comparing it to its default value or evaluating whether it is empty.
4160   * For example:
4161   *
4162   *     if ( ! empty( $deprecated ) ) {
4163   *         _deprecated_argument( __FUNCTION__, '3.0.0' );
4164   *     }
4165   *
4166   * There is a hook deprecated_argument_run that will be called that can be used
4167   * to get the backtrace up to what file and function used the deprecated
4168   * argument.
4169   *
4170   * The current behavior is to trigger a user error if WP_DEBUG is true.
4171   *
4172   * @since 3.0.0
4173   * @access private
4174   *
4175   * @param string $function The function that was called.
4176   * @param string $version  The version of WordPress that deprecated the argument used.
4177   * @param string $message  Optional. A message regarding the change. Default null.
4178   */
4179  function _deprecated_argument( $function, $version, $message = null ) {
4180  
4181      /**
4182       * Fires when a deprecated argument is called.
4183       *
4184       * @since 3.0.0
4185       *
4186       * @param string $function The function that was called.
4187       * @param string $message  A message regarding the change.
4188       * @param string $version  The version of WordPress that deprecated the argument used.
4189       */
4190      do_action( 'deprecated_argument_run', $function, $message, $version );
4191  
4192      /**
4193       * Filters whether to trigger an error for deprecated arguments.
4194       *
4195       * @since 3.0.0
4196       *
4197       * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
4198       */
4199      if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
4200          if ( function_exists( '__' ) ) {
4201              if ( ! is_null( $message ) ) {
4202                  /* translators: 1: PHP function name, 2: version number, 3: optional message regarding the change */
4203                  trigger_error( sprintf( __( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s' ), $function, $version, $message ) );
4204              } else {
4205                  /* translators: 1: PHP function name, 2: version number */
4206                  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 ) );
4207              }
4208          } else {
4209              if ( ! is_null( $message ) ) {
4210                  trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
4211              } else {
4212                  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 ) );
4213              }
4214          }
4215      }
4216  }
4217  
4218  /**
4219   * Marks a deprecated action or filter hook as deprecated and throws a notice.
4220   *
4221   * Use the {@see 'deprecated_hook_run'} action to get the backtrace describing where
4222   * the deprecated hook was called.
4223   *
4224   * Default behavior is to trigger a user error if `WP_DEBUG` is true.
4225   *
4226   * This function is called by the do_action_deprecated() and apply_filters_deprecated()
4227   * functions, and so generally does not need to be called directly.
4228   *
4229   * @since 4.6.0
4230   * @access private
4231   *
4232   * @param string $hook        The hook that was used.
4233   * @param string $version     The version of WordPress that deprecated the hook.
4234   * @param string $replacement Optional. The hook that should have been used.
4235   * @param string $message     Optional. A message regarding the change.
4236   */
4237  function _deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
4238      /**
4239       * Fires when a deprecated hook is called.
4240       *
4241       * @since 4.6.0
4242       *
4243       * @param string $hook        The hook that was called.
4244       * @param string $replacement The hook that should be used as a replacement.
4245       * @param string $version     The version of WordPress that deprecated the argument used.
4246       * @param string $message     A message regarding the change.
4247       */
4248      do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
4249  
4250      /**
4251       * Filters whether to trigger deprecated hook errors.
4252       *
4253       * @since 4.6.0
4254       *
4255       * @param bool $trigger Whether to trigger deprecated hook errors. Requires
4256       *                      `WP_DEBUG` to be defined true.
4257       */
4258      if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
4259          $message = empty( $message ) ? '' : ' ' . $message;
4260          if ( ! is_null( $replacement ) ) {
4261              /* translators: 1: WordPress hook name, 2: version number, 3: alternative hook name */
4262              trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
4263          } else {
4264              /* translators: 1: WordPress hook name, 2: version number */
4265              trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $hook, $version ) . $message );
4266          }
4267      }
4268  }
4269  
4270  /**
4271   * Mark something as being incorrectly called.
4272   *
4273   * There is a hook {@see 'doing_it_wrong_run'} that will be called that can be used
4274   * to get the backtrace up to what file and function called the deprecated
4275   * function.
4276   *
4277   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
4278   *
4279   * @since 3.1.0
4280   * @access private
4281   *
4282   * @param string $function The function that was called.
4283   * @param string $message  A message explaining what has been done incorrectly.
4284   * @param string $version  The version of WordPress where the message was added.
4285   */
4286  function _doing_it_wrong( $function, $message, $version ) {
4287  
4288      /**
4289       * Fires when the given function is being used incorrectly.
4290       *
4291       * @since 3.1.0
4292       *
4293       * @param string $function The function that was called.
4294       * @param string $message  A message explaining what has been done incorrectly.
4295       * @param string $version  The version of WordPress where the message was added.
4296       */
4297      do_action( 'doing_it_wrong_run', $function, $message, $version );
4298  
4299      /**
4300       * Filters whether to trigger an error for _doing_it_wrong() calls.
4301       *
4302       * @since 3.1.0
4303       *
4304       * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
4305       */
4306      if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
4307          if ( function_exists( '__' ) ) {
4308              if ( is_null( $version ) ) {
4309                  $version = '';
4310              } else {
4311                  /* translators: %s: version number */
4312                  $version = sprintf( __( '(This message was added in version %s.)' ), $version );
4313              }
4314              /* translators: %s: Codex URL */
4315              $message .= ' ' . sprintf(
4316                  __( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
4317                  __( 'https://codex.wordpress.org/Debugging_in_WordPress' )
4318              );
4319              /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Version information message */
4320              trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
4321          } else {
4322              if ( is_null( $version ) ) {
4323                  $version = '';
4324              } else {
4325                  $version = sprintf( '(This message was added in version %s.)', $version );
4326              }
4327              $message .= sprintf(
4328                  ' Please see <a href="%s">Debugging in WordPress</a> for more information.',
4329                  'https://codex.wordpress.org/Debugging_in_WordPress'
4330              );
4331              trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
4332          }
4333      }
4334  }
4335  
4336  /**
4337   * Is the server running earlier than 1.5.0 version of lighttpd?
4338   *
4339   * @since 2.5.0
4340   *
4341   * @return bool Whether the server is running lighttpd < 1.5.0.
4342   */
4343  function is_lighttpd_before_150() {
4344      $server_parts    = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
4345      $server_parts[1] = isset( $server_parts[1] ) ? $server_parts[1] : '';
4346      return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
4347  }
4348  
4349  /**
4350   * Does the specified module exist in the Apache config?
4351   *
4352   * @since 2.5.0
4353   *
4354   * @global bool $is_apache
4355   *
4356   * @param string $mod     The module, e.g. mod_rewrite.
4357   * @param bool   $default Optional. The default return value if the module is not found. Default false.
4358   * @return bool Whether the specified module is loaded.
4359   */
4360  function apache_mod_loaded( $mod, $default = false ) {
4361      global $is_apache;
4362  
4363      if ( ! $is_apache ) {
4364          return false;
4365      }
4366  
4367      if ( function_exists( 'apache_get_modules' ) ) {
4368          $mods = apache_get_modules();
4369          if ( in_array( $mod, $mods ) ) {
4370              return true;
4371          }
4372      } elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
4373              ob_start();
4374              phpinfo( 8 );
4375              $phpinfo = ob_get_clean();
4376          if ( false !== strpos( $phpinfo, $mod ) ) {
4377              return true;
4378          }
4379      }
4380      return $default;
4381  }
4382  
4383  /**
4384   * Check if IIS 7+ supports pretty permalinks.
4385   *
4386   * @since 2.8.0
4387   *
4388   * @global bool $is_iis7
4389   *
4390   * @return bool Whether IIS7 supports permalinks.
4391   */
4392  function iis7_supports_permalinks() {
4393      global $is_iis7;
4394  
4395      $supports_permalinks = false;
4396      if ( $is_iis7 ) {
4397          /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
4398           * easily update the xml configuration file, hence we just bail out and tell user that
4399           * pretty permalinks cannot be used.
4400           *
4401           * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
4402           * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
4403           * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
4404           * via ISAPI then pretty permalinks will not work.
4405           */
4406          $supports_permalinks = class_exists( 'DOMDocument', false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( PHP_SAPI == 'cgi-fcgi' );
4407      }
4408  
4409      /**
4410       * Filters whether IIS 7+ supports pretty permalinks.
4411       *
4412       * @since 2.8.0
4413       *
4414       * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
4415       */
4416      return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
4417  }
4418  
4419  /**
4420   * Validates a file name and path against an allowed set of rules.
4421   *
4422   * A return value of `1` means the file path contains directory traversal.
4423   *
4424   * A return value of `2` means the file path contains a Windows drive path.
4425   *
4426   * A return value of `3` means the file is not in the allowed files list.
4427   *
4428   * @since 1.2.0
4429   *
4430   * @param string $file          File path.
4431   * @param array  $allowed_files Optional. List of allowed files.
4432   * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
4433   */
4434  function validate_file( $file, $allowed_files = array() ) {
4435      // `../` on its own is not allowed:
4436      if ( '../' === $file ) {
4437          return 1;
4438      }
4439  
4440      // More than one occurence of `../` is not allowed:
4441      if ( preg_match_all( '#\.\./#', $file, $matches, PREG_SET_ORDER ) && ( count( $matches ) > 1 ) ) {
4442          return 1;
4443      }
4444  
4445      // `../` which does not occur at the end of the path is not allowed:
4446      if ( false !== strpos( $file, '../' ) && '../' !== mb_substr( $file, -3, 3 ) ) {
4447          return 1;
4448      }
4449  
4450      // Files not in the allowed file list are not allowed:
4451      if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) ) {
4452          return 3;
4453      }
4454  
4455      // Absolute Windows drive paths are not allowed:
4456      if ( ':' == substr( $file, 1, 1 ) ) {
4457          return 2;
4458      }
4459  
4460      return 0;
4461  }
4462  
4463  /**
4464   * Whether to force SSL used for the Administration Screens.
4465   *
4466   * @since 2.6.0
4467   *
4468   * @staticvar bool $forced
4469   *
4470   * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
4471   * @return bool True if forced, false if not forced.
4472   */
4473  function force_ssl_admin( $force = null ) {
4474      static $forced = false;
4475  
4476      if ( ! is_null( $force ) ) {
4477          $old_forced = $forced;
4478          $forced     = $force;
4479          return $old_forced;
4480      }
4481  
4482      return $forced;
4483  }
4484  
4485  /**
4486   * Guess the URL for the site.
4487   *
4488   * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
4489   * directory.
4490   *
4491   * @since 2.6.0
4492   *
4493   * @return string The guessed URL.
4494   */
4495  function wp_guess_url() {
4496      if ( defined( 'WP_SITEURL' ) && '' != WP_SITEURL ) {
4497          $url = WP_SITEURL;
4498      } else {
4499          $abspath_fix         = str_replace( '\\', '/', ABSPATH );
4500          $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
4501  
4502          // The request is for the admin
4503          if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
4504              $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
4505  
4506              // The request is for a file in ABSPATH
4507          } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
4508              // Strip off any file/query params in the path
4509              $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
4510  
4511          } else {
4512              if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
4513                  // Request is hitting a file inside ABSPATH
4514                  $directory = str_replace( ABSPATH, '', $script_filename_dir );
4515                  // Strip off the sub directory, and any file/query params
4516                  $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '', $_SERVER['REQUEST_URI'] );
4517              } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
4518                  // Request is hitting a file above ABSPATH
4519                  $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
4520                  // Strip off any file/query params from the path, appending the sub directory to the installation
4521                  $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['REQUEST_URI'] ) . $subdirectory;
4522              } else {
4523                  $path = $_SERVER['REQUEST_URI'];
4524              }
4525          }
4526  
4527          $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
4528          $url    = $schema . $_SERVER['HTTP_HOST'] . $path;
4529      }
4530  
4531      return rtrim( $url, '/' );
4532  }
4533  
4534  /**
4535   * Temporarily suspend cache additions.
4536   *
4537   * Stops more data being added to the cache, but still allows cache retrieval.
4538   * This is useful for actions, such as imports, when a lot of data would otherwise
4539   * be almost uselessly added to the cache.
4540   *
4541   * Suspension lasts for a single page load at most. Remember to call this
4542   * function again if you wish to re-enable cache adds earlier.
4543   *
4544   * @since 3.3.0
4545   *
4546   * @staticvar bool $_suspend
4547   *
4548   * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
4549   * @return bool The current suspend setting
4550   */
4551  function wp_suspend_cache_addition( $suspend = null ) {
4552      static $_suspend = false;
4553  
4554      if ( is_bool( $suspend ) ) {
4555          $_suspend = $suspend;
4556      }
4557  
4558      return $_suspend;
4559  }
4560  
4561  /**
4562   * Suspend cache invalidation.
4563   *
4564   * Turns cache invalidation on and off. Useful during imports where you don't want to do
4565   * invalidations every time a post is inserted. Callers must be sure that what they are
4566   * doing won't lead to an inconsistent cache when invalidation is suspended.
4567   *
4568   * @since 2.7.0
4569   *
4570   * @global bool $_wp_suspend_cache_invalidation
4571   *
4572   * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
4573   * @return bool The current suspend setting.
4574   */
4575  function wp_suspend_cache_invalidation( $suspend = true ) {
4576      global $_wp_suspend_cache_invalidation;
4577  
4578      $current_suspend                = $_wp_suspend_cache_invalidation;
4579      $_wp_suspend_cache_invalidation = $suspend;
4580      return $current_suspend;
4581  }
4582  
4583  /**
4584   * Determine whether a site is the main site of the current network.
4585   *
4586   * @since 3.0.0
4587   * @since 4.9.0 The `$network_id` parameter was added.
4588   *
4589   * @param int $site_id    Optional. Site ID to test. Defaults to current site.
4590   * @param int $network_id Optional. Network ID of the network to check for.
4591   *                        Defaults to current network.
4592   * @return bool True if $site_id is the main site of the network, or if not
4593   *              running Multisite.
4594   */
4595  function is_main_site( $site_id = null, $network_id = null ) {
4596      if ( ! is_multisite() ) {
4597          return true;
4598      }
4599  
4600      if ( ! $site_id ) {
4601          $site_id = get_current_blog_id();
4602      }
4603  
4604      $site_id = (int) $site_id;
4605  
4606      return $site_id === get_main_site_id( $network_id );
4607  }
4608  
4609  /**
4610   * Gets the main site ID.
4611   *
4612   * @since 4.9.0
4613   *
4614   * @param int $network_id Optional. The ID of the network for which to get the main site.
4615   *                        Defaults to the current network.
4616   * @return int The ID of the main site.
4617   */
4618  function get_main_site_id( $network_id = null ) {
4619      if ( ! is_multisite() ) {
4620          return get_current_blog_id();
4621      }
4622  
4623      $network = get_network( $network_id );
4624      if ( ! $network ) {
4625          return 0;
4626      }
4627  
4628      return $network->site_id;
4629  }
4630  
4631  /**
4632   * Determine whether a network is the main network of the Multisite installation.
4633   *
4634   * @since 3.7.0
4635   *
4636   * @param int $network_id Optional. Network ID to test. Defaults to current network.
4637   * @return bool True if $network_id is the main network, or if not running Multisite.
4638   */
4639  function is_main_network( $network_id = null ) {
4640      if ( ! is_multisite() ) {
4641          return true;
4642      }
4643  
4644      if ( null === $network_id ) {
4645          $network_id = get_current_network_id();
4646      }
4647  
4648      $network_id = (int) $network_id;
4649  
4650      return ( $network_id === get_main_network_id() );
4651  }
4652  
4653  /**
4654   * Get the main network ID.
4655   *
4656   * @since 4.3.0
4657   *
4658   * @return int The ID of the main network.
4659   */
4660  function get_main_network_id() {
4661      if ( ! is_multisite() ) {
4662          return 1;
4663      }
4664  
4665      $current_network = get_network();
4666  
4667      if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
4668          $main_network_id = PRIMARY_NETWORK_ID;
4669      } elseif ( isset( $current_network->id ) && 1 === (int) $current_network->id ) {
4670          // If the current network has an ID of 1, assume it is the main network.
4671          $main_network_id = 1;
4672      } else {
4673          $_networks       = get_networks(
4674              array(
4675                  'fields' => 'ids',
4676                  'number' => 1,
4677              )
4678          );
4679          $main_network_id = array_shift( $_networks );
4680      }
4681  
4682      /**
4683       * Filters the main network ID.
4684       *
4685       * @since 4.3.0
4686       *
4687       * @param int $main_network_id The ID of the main network.
4688       */
4689      return (int) apply_filters( 'get_main_network_id', $main_network_id );
4690  }
4691  
4692  /**
4693   * Determine whether global terms are enabled.
4694   *
4695   * @since 3.0.0
4696   *
4697   * @staticvar bool $global_terms
4698   *
4699   * @return bool True if multisite and global terms enabled.
4700   */
4701  function global_terms_enabled() {
4702      if ( ! is_multisite() ) {
4703          return false;
4704      }
4705  
4706      static $global_terms = null;
4707      if ( is_null( $global_terms ) ) {
4708  
4709          /**
4710           * Filters whether global terms are enabled.
4711           *
4712           * Passing a non-null value to the filter will effectively short-circuit the function,
4713           * returning the value of the 'global_terms_enabled' site option instead.
4714           *
4715           * @since 3.0.0
4716           *
4717           * @param null $enabled Whether global terms are enabled.
4718           */
4719          $filter = apply_filters( 'global_terms_enabled', null );
4720          if ( ! is_null( $filter ) ) {
4721              $global_terms = (bool) $filter;
4722          } else {
4723              $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
4724          }
4725      }
4726      return $global_terms;
4727  }
4728  
4729  /**
4730   * Determines whether site meta is enabled.
4731   *
4732   * This function checks whether the 'blogmeta' database table exists. The result is saved as
4733   * a setting for the main network, making it essentially a global setting. Subsequent requests
4734   * will refer to this setting instead of running the query.
4735   *
4736   * @since 5.0.0
4737   *
4738   * @global wpdb $wpdb WordPress database abstraction object.
4739   *
4740   * @return bool True if site meta is supported, false otherwise.
4741   */
4742  function is_site_meta_supported() {
4743      global $wpdb;
4744  
4745      if ( ! is_multisite() ) {
4746          return false;
4747      }
4748  
4749      $network_id = get_main_network_id();
4750  
4751      $supported = get_network_option( $network_id, 'site_meta_supported', false );
4752      if ( false === $supported ) {
4753          $supported = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->blogmeta}'" ) ? 1 : 0;
4754  
4755          update_network_option( $network_id, 'site_meta_supported', $supported );
4756      }
4757  
4758      return (bool) $supported;
4759  }
4760  
4761  /**
4762   * gmt_offset modification for smart timezone handling.
4763   *
4764   * Overrides the gmt_offset option if we have a timezone_string available.
4765   *
4766   * @since 2.8.0
4767   *
4768   * @return float|false Timezone GMT offset, false otherwise.
4769   */
4770  function wp_timezone_override_offset() {
4771      if ( ! $timezone_string = get_option( 'timezone_string' ) ) {
4772          return false;
4773      }
4774  
4775      $timezone_object = timezone_open( $timezone_string );
4776      $datetime_object = date_create();
4777      if ( false === $timezone_object || false === $datetime_object ) {
4778          return false;
4779      }
4780      return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
4781  }
4782  
4783  /**
4784   * Sort-helper for timezones.
4785   *
4786   * @since 2.9.0
4787   * @access private
4788   *
4789   * @param array $a
4790   * @param array $b
4791   * @return int
4792   */
4793  function _wp_timezone_choice_usort_callback( $a, $b ) {
4794      // Don't use translated versions of Etc
4795      if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
4796          // Make the order of these more like the old dropdown
4797          if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4798              return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
4799          }
4800          if ( 'UTC' === $a['city'] ) {
4801              if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4802                  return 1;
4803              }
4804              return -1;
4805          }
4806          if ( 'UTC' === $b['city'] ) {
4807              if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
4808                  return -1;
4809              }
4810              return 1;
4811          }
4812          return strnatcasecmp( $a['city'], $b['city'] );
4813      }
4814      if ( $a['t_continent'] == $b['t_continent'] ) {
4815          if ( $a['t_city'] == $b['t_city'] ) {
4816              return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
4817          }
4818          return strnatcasecmp( $a['t_city'], $b['t_city'] );
4819      } else {
4820          // Force Etc to the bottom of the list
4821          if ( 'Etc' === $a['continent'] ) {
4822              return 1;
4823          }
4824          if ( 'Etc' === $b['continent'] ) {
4825              return -1;
4826          }
4827          return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
4828      }
4829  }
4830  
4831  /**
4832   * Gives a nicely-formatted list of timezone strings.
4833   *
4834   * @since 2.9.0
4835   * @since 4.7.0 Added the `$locale` parameter.
4836   *
4837   * @staticvar bool $mo_loaded
4838   * @staticvar string $locale_loaded
4839   *
4840   * @param string $selected_zone Selected timezone.
4841   * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
4842   * @return string
4843   */
4844  function wp_timezone_choice( $selected_zone, $locale = null ) {
4845      static $mo_loaded = false, $locale_loaded = null;
4846  
4847      $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' );
4848  
4849      // Load translations for continents and cities.
4850      if ( ! $mo_loaded || $locale !== $locale_loaded ) {
4851          $locale_loaded = $locale ? $locale : get_locale();
4852          $mofile        = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
4853          unload_textdomain( 'continents-cities' );
4854          load_textdomain( 'continents-cities', $mofile );
4855          $mo_loaded = true;
4856      }
4857  
4858      $zonen = array();
4859      foreach ( timezone_identifiers_list() as $zone ) {
4860          $zone = explode( '/', $zone );
4861          if ( ! in_array( $zone[0], $continents ) ) {
4862              continue;
4863          }
4864  
4865          // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
4866          $exists    = array(
4867              0 => ( isset( $zone[0] ) && $zone[0] ),
4868              1 => ( isset( $zone[1] ) && $zone[1] ),
4869              2 => ( isset( $zone[2] ) && $zone[2] ),
4870          );
4871          $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
4872          $exists[4] = ( $exists[1] && $exists[3] );
4873          $exists[5] = ( $exists[2] && $exists[3] );
4874  
4875          $zonen[] = array(
4876              'continent'   => ( $exists[0] ? $zone[0] : '' ),
4877              'city'        => ( $exists[1] ? $zone[1] : '' ),
4878              'subcity'     => ( $exists[2] ? $zone[2] : '' ),
4879              't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
4880              't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
4881              't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' ),
4882          );
4883      }
4884      usort( $zonen, '_wp_timezone_choice_usort_callback' );
4885  
4886      $structure = array();
4887  
4888      if ( empty( $selected_zone ) ) {
4889          $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
4890      }
4891  
4892      foreach ( $zonen as $key => $zone ) {
4893          // Build value in an array to join later
4894          $value = array( $zone['continent'] );
4895  
4896          if ( empty( $zone['city'] ) ) {
4897              // It's at the continent level (generally won't happen)
4898              $display = $zone['t_continent'];
4899          } else {
4900              // It's inside a continent group
4901  
4902              // Continent optgroup
4903              if ( ! isset( $zonen[ $key - 1 ] ) || $zonen[ $key - 1 ]['continent'] !== $zone['continent'] ) {
4904                  $label       = $zone['t_continent'];
4905                  $structure[] = '<optgroup label="' . esc_attr( $label ) . '">';
4906              }
4907  
4908              // Add the city to the value
4909              $value[] = $zone['city'];
4910  
4911              $display = $zone['t_city'];
4912              if ( ! empty( $zone['subcity'] ) ) {
4913                  // Add the subcity to the value
4914                  $value[]  = $zone['subcity'];
4915                  $display .= ' - ' . $zone['t_subcity'];
4916              }
4917          }
4918  
4919          // Build the value
4920          $value    = join( '/', $value );
4921          $selected = '';
4922          if ( $value === $selected_zone ) {
4923              $selected = 'selected="selected" ';
4924          }
4925          $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . '</option>';
4926  
4927          // Close continent optgroup
4928          if ( ! empty( $zone['city'] ) && ( ! isset( $zonen[ $key + 1 ] ) || ( isset( $zonen[ $key + 1 ] ) && $zonen[ $key + 1 ]['continent'] !== $zone['continent'] ) ) ) {
4929              $structure[] = '</optgroup>';
4930          }
4931      }
4932  
4933      // Do UTC
4934      $structure[] = '<optgroup label="' . esc_attr__( 'UTC' ) . '">';
4935      $selected    = '';
4936      if ( 'UTC' === $selected_zone ) {
4937          $selected = 'selected="selected" ';
4938      }
4939      $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __( 'UTC' ) . '</option>';
4940      $structure[] = '</optgroup>';
4941  
4942      // Do manual UTC offsets
4943      $structure[]  = '<optgroup label="' . esc_attr__( 'Manual Offsets' ) . '">';
4944      $offset_range = array(
4945          -12,
4946          -11.5,
4947          -11,
4948          -10.5,
4949          -10,
4950          -9.5,
4951          -9,
4952          -8.5,
4953          -8,
4954          -7.5,
4955          -7,
4956          -6.5,
4957          -6,
4958          -5.5,
4959          -5,
4960          -4.5,
4961          -4,
4962          -3.5,
4963          -3,
4964          -2.5,
4965          -2,
4966          -1.5,
4967          -1,
4968          -0.5,
4969          0,
4970          0.5,
4971          1,
4972          1.5,
4973          2,
4974          2.5,
4975          3,
4976          3.5,
4977          4,
4978          4.5,
4979          5,
4980          5.5,
4981          5.75,
4982          6,
4983          6.5,
4984          7,
4985          7.5,
4986          8,
4987          8.5,
4988          8.75,
4989          9,
4990          9.5,
4991          10,
4992          10.5,
4993          11,
4994          11.5,
4995          12,
4996          12.75,
4997          13,
4998          13.75,
4999          14,
5000      );
5001      foreach ( $offset_range as $offset ) {
5002          if ( 0 <= $offset ) {
5003              $offset_name = '+' . $offset;
5004          } else {
5005              $offset_name = (string) $offset;
5006          }
5007  
5008          $offset_value = $offset_name;
5009          $offset_name  = str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), $offset_name );
5010          $offset_name  = 'UTC' . $offset_name;
5011          $offset_value = 'UTC' . $offset_value;
5012          $selected     = '';
5013          if ( $offset_value === $selected_zone ) {
5014              $selected = 'selected="selected" ';
5015          }
5016          $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . '</option>';
5017  
5018      }
5019      $structure[] = '</optgroup>';
5020  
5021      return join( "\n", $structure );
5022  }
5023  
5024  /**
5025   * Strip close comment and close php tags from file headers used by WP.
5026   *
5027   * @since 2.8.0
5028   * @access private
5029   *
5030   * @see https://core.trac.wordpress.org/ticket/8497
5031   *
5032   * @param string $str Header comment to clean up.
5033   * @return string
5034   */
5035  function _cleanup_header_comment( $str ) {
5036      return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
5037  }
5038  
5039  /**
5040   * Permanently delete comments or posts of any type that have held a status
5041   * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
5042   *
5043   * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
5044   *
5045   * @since 2.9.0
5046   *
5047   * @global wpdb $wpdb WordPress database abstraction object.
5048   */
5049  function wp_scheduled_delete() {
5050      global $wpdb;
5051  
5052      $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
5053  
5054      $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 );
5055  
5056      foreach ( (array) $posts_to_delete as $post ) {
5057          $post_id = (int) $post['post_id'];
5058          if ( ! $post_id ) {
5059              continue;
5060          }
5061  
5062          $del_post = get_post( $post_id );
5063  
5064          if ( ! $del_post || 'trash' != $del_post->post_status ) {
5065              delete_post_meta( $post_id, '_wp_trash_meta_status' );
5066              delete_post_meta( $post_id, '_wp_trash_meta_time' );
5067          } else {
5068              wp_delete_post( $post_id );
5069          }
5070      }
5071  
5072      $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 );
5073  
5074      foreach ( (array) $comments_to_delete as $comment ) {
5075          $comment_id = (int) $comment['comment_id'];
5076          if ( ! $comment_id ) {
5077              continue;
5078          }
5079  
5080          $del_comment = get_comment( $comment_id );
5081  
5082          if ( ! $del_comment || 'trash' != $del_comment->comment_approved ) {
5083              delete_comment_meta( $comment_id, '_wp_trash_meta_time' );
5084              delete_comment_meta( $comment_id, '_wp_trash_meta_status' );
5085          } else {
5086              wp_delete_comment( $del_comment );
5087          }
5088      }
5089  }
5090  
5091  /**
5092   * Retrieve metadata from a file.
5093   *
5094   * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
5095   * Each piece of metadata must be on its own line. Fields can not span multiple
5096   * lines, the value will get cut at the end of the first line.
5097   *
5098   * If the file data is not within that first 8kiB, then the author should correct
5099   * their plugin file and move the data headers to the top.
5100   *
5101   * @link https://codex.wordpress.org/File_Header
5102   *
5103   * @since 2.9.0
5104   *
5105   * @param string $file            Absolute path to the file.
5106   * @param array  $default_headers List of headers, in the format `array('HeaderKey' => 'Header Name')`.
5107   * @param string $context         Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
5108   *                                Default empty.
5109   * @return array Array of file headers in `HeaderKey => Header Value` format.
5110   */
5111  function get_file_data( $file, $default_headers, $context = '' ) {
5112      // We don't need to write to the file, so just open for reading.
5113      $fp = fopen( $file, 'r' );
5114  
5115      // Pull only the first 8kiB of the file in.
5116      $file_data = fread( $fp, 8192 );
5117  
5118      // PHP will close file handle, but we are good citizens.
5119      fclose( $fp );
5120  
5121      // Make sure we catch CR-only line endings.
5122      $file_data = str_replace( "\r", "\n", $file_data );
5123  
5124      /**
5125       * Filters extra file headers by context.
5126       *
5127       * The dynamic portion of the hook name, `$context`, refers to
5128       * the context where extra headers might be loaded.
5129       *
5130       * @since 2.9.0
5131       *
5132       * @param array $extra_context_headers Empty array by default.
5133       */
5134      if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
5135          $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
5136          $all_headers   = array_merge( $extra_headers, (array) $default_headers );
5137      } else {
5138          $all_headers = $default_headers;
5139      }
5140  
5141      foreach ( $all_headers as $field => $regex ) {
5142          if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] ) {
5143              $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
5144          } else {
5145              $all_headers[ $field ] = '';
5146          }
5147      }
5148  
5149      return $all_headers;
5150  }
5151  
5152  /**
5153   * Returns true.
5154   *
5155   * Useful for returning true to filters easily.
5156   *
5157   * @since 3.0.0
5158   *
5159   * @see __return_false()
5160   *
5161   * @return true True.
5162   */
5163  function __return_true() {
5164      return true;
5165  }
5166  
5167  /**
5168   * Returns false.
5169   *
5170   * Useful for returning false to filters easily.
5171   *
5172   * @since 3.0.0
5173   *
5174   * @see __return_true()
5175   *
5176   * @return false False.
5177   */
5178  function __return_false() {
5179      return false;
5180  }
5181  
5182  /**
5183   * Returns 0.
5184   *
5185   * Useful for returning 0 to filters easily.
5186   *
5187   * @since 3.0.0
5188   *
5189   * @return int 0.
5190   */
5191  function __return_zero() {
5192      return 0;
5193  }
5194  
5195  /**
5196   * Returns an empty array.
5197   *
5198   * Useful for returning an empty array to filters easily.
5199   *
5200   * @since 3.0.0
5201   *
5202   * @return array Empty array.
5203   */
5204  function __return_empty_array() {
5205      return array();
5206  }
5207  
5208  /**
5209   * Returns null.
5210   *
5211   * Useful for returning null to filters easily.
5212   *
5213   * @since 3.4.0
5214   *
5215   * @return null Null value.
5216   */
5217  function __return_null() {
5218      return null;
5219  }
5220  
5221  /**
5222   * Returns an empty string.
5223   *
5224   * Useful for returning an empty string to filters easily.
5225   *
5226   * @since 3.7.0
5227   *
5228   * @see __return_null()
5229   *
5230   * @return string Empty string.
5231   */
5232  function __return_empty_string() {
5233      return '';
5234  }
5235  
5236  /**
5237   * Send a HTTP header to disable content type sniffing in browsers which support it.
5238   *
5239   * @since 3.0.0
5240   *
5241   * @see https://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
5242   * @see https://src.chromium.org/viewvc/chrome?view=rev&revision=6985
5243   */
5244  function send_nosniff_header() {
5245      @header( 'X-Content-Type-Options: nosniff' );
5246  }
5247  
5248  /**
5249   * Return a MySQL expression for selecting the week number based on the start_of_week option.
5250   *
5251   * @ignore
5252   * @since 3.0.0
5253   *
5254   * @param string $column Database column.
5255   * @return string SQL clause.
5256   */
5257  function _wp_mysql_week( $column ) {
5258      switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
5259          case 1:
5260              return "WEEK( $column, 1 )";
5261          case 2:
5262          case 3:
5263          case 4:
5264          case 5:
5265          case 6:
5266              return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
5267          case 0:
5268          default:
5269              return "WEEK( $column, 0 )";
5270      }
5271  }
5272  
5273  /**
5274   * Find hierarchy loops using a callback function that maps object IDs to parent IDs.
5275   *
5276   * @since 3.1.0
5277   * @access private
5278   *
5279   * @param callable $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
5280   * @param int      $start         The ID to start the loop check at.
5281   * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
5282   *                                Use null to always use $callback
5283   * @param array    $callback_args Optional. Additional arguments to send to $callback.
5284   * @return array IDs of all members of loop.
5285   */
5286  function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
5287      $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
5288  
5289      if ( ! $arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) ) {
5290          return array();
5291      }
5292  
5293      return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
5294  }
5295  
5296  /**
5297   * Use the "The Tortoise and the Hare" algorithm to detect loops.
5298   *
5299   * For every step of the algorithm, the hare takes two steps and the tortoise one.
5300   * If the hare ever laps the tortoise, there must be a loop.
5301   *
5302   * @since 3.1.0
5303   * @access private
5304   *
5305   * @param callable $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
5306   * @param int      $start         The ID to start the loop check at.
5307   * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
5308   *                                Default empty array.
5309   * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
5310   * @param bool     $_return_loop  Optional. Return loop members or just detect presence of loop? Only set
5311   *                                to true if you already know the given $start is part of a loop (otherwise
5312   *                                the returned array might include branches). Default false.
5313   * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
5314   *               $_return_loop
5315   */
5316  function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
5317      $tortoise = $hare = $evanescent_hare = $start;
5318      $return   = array();
5319  
5320      // Set evanescent_hare to one past hare
5321      // Increment hare two steps
5322      while (
5323          $tortoise
5324      &&
5325          ( $evanescent_hare = isset( $override[ $hare ] ) ? $override[ $hare ] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
5326      &&
5327          ( $hare = isset( $override[ $evanescent_hare ] ) ? $override[ $evanescent_hare ] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
5328      ) {
5329          if ( $_return_loop ) {
5330              $return[ $tortoise ] = $return[ $evanescent_hare ] = $return[ $hare ] = true;
5331          }
5332  
5333          // tortoise got lapped - must be a loop
5334          if ( $tortoise == $evanescent_hare || $tortoise == $hare ) {
5335              return $_return_loop ? $return : $tortoise;
5336          }
5337  
5338          // Increment tortoise by one step
5339          $tortoise = isset( $override[ $tortoise ] ) ? $override[ $tortoise ] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
5340      }
5341  
5342      return false;
5343  }
5344  
5345  /**
5346   * Send a HTTP header to limit rendering of pages to same origin iframes.
5347   *
5348   * @since 3.1.3
5349   *
5350   * @see https://developer.mozilla.org/en/the_x-frame-options_response_header
5351   */
5352  function send_frame_options_header() {
5353      @header( 'X-Frame-Options: SAMEORIGIN' );
5354  }
5355  
5356  /**
5357   * Retrieve a list of protocols to allow in HTML attributes.
5358   *
5359   * @since 3.3.0
5360   * @since 4.3.0 Added 'webcal' to the protocols array.
5361   * @since 4.7.0 Added 'urn' to the protocols array.
5362   *
5363   * @see wp_kses()
5364   * @see esc_url()
5365   *
5366   * @staticvar array $protocols
5367   *
5368   * @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
5369   *                  'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
5370   *                  'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'. This covers
5371   *                  all common link protocols, except for 'javascript' which should not be
5372   *                  allowed for untrusted users.
5373   */
5374  function wp_allowed_protocols() {
5375      static $protocols = array();
5376  
5377      if ( empty( $protocols ) ) {
5378          $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
5379      }
5380  
5381      if ( ! did_action( 'wp_loaded' ) ) {
5382          /**
5383           * Filters the list of protocols allowed in HTML attributes.
5384           *
5385           * @since 3.0.0
5386           *
5387           * @param array $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
5388           */
5389          $protocols = array_unique( (array) apply_filters( 'kses_allowed_protocols', $protocols ) );
5390      }
5391  
5392      return $protocols;
5393  }
5394  
5395  /**
5396   * Return a comma-separated string of functions that have been called to get
5397   * to the current point in code.
5398   *
5399   * @since 3.4.0
5400   *
5401   * @see https://core.trac.wordpress.org/ticket/19589
5402   *
5403   * @staticvar array $truncate_paths Array of paths to truncate.
5404   *
5405   * @param string $ignore_class Optional. A class to ignore all function calls within - useful
5406   *                             when you want to just give info about the callee. Default null.
5407   * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
5408   *                             back to the source of the issue. Default 0.
5409   * @param bool   $pretty       Optional. Whether or not you want a comma separated string or raw
5410   *                             array returned. Default true.
5411   * @return string|array Either a string containing a reversed comma separated trace or an array
5412   *                      of individual calls.
5413   */
5414  function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
5415      static $truncate_paths;
5416  
5417      if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) ) {
5418          $trace = debug_backtrace( false );
5419      } else {
5420          $trace = debug_backtrace();
5421      }
5422  
5423      $caller      = array();
5424      $check_class = ! is_null( $ignore_class );
5425      $skip_frames++; // skip this function
5426  
5427      if ( ! isset( $truncate_paths ) ) {
5428          $truncate_paths = array(
5429              wp_normalize_path( WP_CONTENT_DIR ),
5430              wp_normalize_path( ABSPATH )
5431          );
5432      }
5433  
5434      foreach ( $trace as $call ) {
5435          if ( $skip_frames > 0 ) {
5436              $skip_frames--;
5437          } elseif ( isset( $call['class'] ) ) {
5438              if ( $check_class && $ignore_class == $call['class'] ) {
5439                  continue; // Filter out calls
5440              }
5441  
5442              $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
5443          } else {
5444              if ( in_array( $call['function'], array( 'do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array' ) ) ) {
5445                  $caller[] = "{$call['function']}('{$call['args'][0]}')";
5446              } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
5447                  $filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
5448                  $caller[] = $call['function'] . "('" . str_replace( $truncate_paths, '', wp_normalize_path( $filename ) ) . "')";
5449              } else {
5450                  $caller[] = $call['function'];
5451              }
5452          }
5453      }
5454      if ( $pretty ) {
5455          return join( ', ', array_reverse( $caller ) );
5456      } else {
5457          return $caller;
5458      }
5459  }
5460  
5461  /**
5462   * Retrieve IDs that are not already present in the cache.
5463   *
5464   * @since 3.4.0
5465   * @access private
5466   *
5467   * @param int[]  $object_ids Array of IDs.
5468   * @param string $cache_key  The cache bucket to check against.
5469   * @return int[] Array of IDs not present in the cache.
5470   */
5471  function _get_non_cached_ids( $object_ids, $cache_key ) {
5472      $clean = array();
5473      foreach ( $object_ids as $id ) {
5474          $id = (int) $id;
5475          if ( ! wp_cache_get( $id, $cache_key ) ) {
5476              $clean[] = $id;
5477          }
5478      }
5479  
5480      return $clean;
5481  }
5482  
5483  /**
5484   * Test if the current device has the capability to upload files.
5485   *
5486   * @since 3.4.0
5487   * @access private
5488   *
5489   * @return bool Whether the device is able to upload files.
5490   */
5491  function _device_can_upload() {
5492      if ( ! wp_is_mobile() ) {
5493          return true;
5494      }
5495  
5496      $ua = $_SERVER['HTTP_USER_AGENT'];
5497  
5498      if ( strpos( $ua, 'iPhone' ) !== false
5499          || strpos( $ua, 'iPad' ) !== false
5500          || strpos( $ua, 'iPod' ) !== false ) {
5501              return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
5502      }
5503  
5504      return true;
5505  }
5506  
5507  /**
5508   * Test if a given path is a stream URL
5509   *
5510   * @since 3.5.0
5511   *
5512   * @param string $path The resource path or URL.
5513   * @return bool True if the path is a stream URL.
5514   */
5515  function wp_is_stream( $path ) {
5516      $wrappers    = stream_get_wrappers();
5517      $wrappers    = array_map( 'preg_quote', $wrappers );
5518      $wrappers_re = '(' . join( '|', $wrappers ) . ')';
5519  
5520      return preg_match( "!^$wrappers_re://!", $path ) === 1;
5521  }
5522  
5523  /**
5524   * Test if the supplied date is valid for the Gregorian calendar.
5525   *
5526   * @since 3.5.0
5527   *
5528   * @see checkdate()
5529   *
5530   * @param  int    $month       Month number.
5531   * @param  int    $day         Day number.
5532   * @param  int    $year        Year number.
5533   * @param  string $source_date The date to filter.
5534   * @return bool True if valid date, false if not valid date.
5535   */
5536  function wp_checkdate( $month, $day, $year, $source_date ) {
5537      /**
5538       * Filters whether the given date is valid for the Gregorian calendar.
5539       *
5540       * @since 3.5.0
5541       *
5542       * @param bool   $checkdate   Whether the given date is valid.
5543       * @param string $source_date Date to check.
5544       */
5545      return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
5546  }
5547  
5548  /**
5549   * Load the auth check for monitoring whether the user is still logged in.
5550   *
5551   * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
5552   *
5553   * This is disabled for certain screens where a login screen could cause an
5554   * inconvenient interruption. A filter called {@see 'wp_auth_check_load'} can be used
5555   * for fine-grained control.
5556   *
5557   * @since 3.6.0
5558   */
5559  function wp_auth_check_load() {
5560      if ( ! is_admin() && ! is_user_logged_in() ) {
5561          return;
5562      }
5563  
5564      if ( defined( 'IFRAME_REQUEST' ) ) {
5565          return;
5566      }
5567  
5568      $screen = get_current_screen();
5569      $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
5570      $show   = ! in_array( $screen->id, $hidden );
5571  
5572      /**
5573       * Filters whether to load the authentication check.
5574       *
5575       * Passing a falsey value to the filter will effectively short-circuit
5576       * loading the authentication check.
5577       *
5578       * @since 3.6.0
5579       *
5580       * @param bool      $show   Whether to load the authentication check.
5581       * @param WP_Screen $screen The current screen object.
5582       */
5583      if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
5584          wp_enqueue_style( 'wp-auth-check' );
5585          wp_enqueue_script( 'wp-auth-check' );
5586  
5587          add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
5588          add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
5589      }
5590  }
5591  
5592  /**
5593   * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
5594   *
5595   * @since 3.6.0
5596   */
5597  function wp_auth_check_html() {
5598      $login_url      = wp_login_url();
5599      $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
5600      $same_domain    = ( strpos( $login_url, $current_domain ) === 0 );
5601  
5602      /**
5603       * Filters whether the authentication check originated at the same domain.
5604       *
5605       * @since 3.6.0
5606       *
5607       * @param bool $same_domain Whether the authentication check originated at the same domain.
5608       */
5609      $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
5610      $wrap_class  = $same_domain ? 'hidden' : 'hidden fallback';
5611  
5612      ?>
5613      <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
5614      <div id="wp-auth-check-bg"></div>
5615      <div id="wp-auth-check">
5616      <button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text"><?php _e( 'Close dialog' ); ?></span></button>
5617      <?php
5618  
5619      if ( $same_domain ) {
5620          $login_src = add_query_arg(
5621              array(
5622                  'interim-login' => '1',
5623                  'wp_lang'       => get_user_locale(),
5624              ), $login_url
5625          );
5626          ?>
5627          <div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( $login_src ); ?>"></div>
5628          <?php
5629      }
5630  
5631      ?>
5632      <div class="wp-auth-fallback">
5633          <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e( 'Session expired' ); ?></b></p>
5634          <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e( 'Please log in again.' ); ?></a>
5635          <?php _e( 'The login page will open in a new tab. After logging in you can close it and return to this page.' ); ?></p>
5636      </div>
5637      </div>
5638      </div>
5639      <?php
5640  }
5641  
5642  /**
5643   * Check whether a user is still logged in, for the heartbeat.
5644   *
5645   * Send a result that shows a log-in box if the user is no longer logged in,
5646   * or if their cookie is within the grace period.
5647   *
5648   * @since 3.6.0
5649   *
5650   * @global int $login_grace_period
5651   *
5652   * @param array $response  The Heartbeat response.
5653   * @return array $response The Heartbeat response with 'wp-auth-check' value set.
5654   */
5655  function wp_auth_check( $response ) {
5656      $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
5657      return $response;
5658  }
5659  
5660  /**
5661   * Return RegEx body to liberally match an opening HTML tag.
5662   *
5663   * Matches an opening HTML tag that:
5664   * 1. Is self-closing or
5665   * 2. Has no body but has a closing tag of the same name or
5666   * 3. Contains a body and a closing tag of the same name
5667   *
5668   * Note: this RegEx does not balance inner tags and does not attempt
5669   * to produce valid HTML
5670   *
5671   * @since 3.6.0
5672   *
5673   * @param string $tag An HTML tag name. Example: 'video'.
5674   * @return string Tag RegEx.
5675   */
5676  function get_tag_regex( $tag ) {
5677      if ( empty( $tag ) ) {
5678          return;
5679      }
5680      return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
5681  }
5682  
5683  /**
5684   * Retrieve a canonical form of the provided charset appropriate for passing to PHP
5685   * functions such as htmlspecialchars() and charset html attributes.
5686   *
5687   * @since 3.6.0
5688   * @access private
5689   *
5690   * @see https://core.trac.wordpress.org/ticket/23688
5691   *
5692   * @param string $charset A charset name.
5693   * @return string The canonical form of the charset.
5694   */
5695  function _canonical_charset( $charset ) {
5696      if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset ) ) {
5697  
5698          return 'UTF-8';
5699      }
5700  
5701      if ( 'iso-8859-1' === strtolower( $charset ) || 'iso8859-1' === strtolower( $charset ) ) {
5702  
5703          return 'ISO-8859-1';
5704      }
5705  
5706      return $charset;
5707  }
5708  
5709  /**
5710   * Set the mbstring internal encoding to a binary safe encoding when func_overload
5711   * is enabled.
5712   *
5713   * When mbstring.func_overload is in use for multi-byte encodings, the results from
5714   * strlen() and similar functions respect the utf8 characters, causing binary data
5715   * to return incorrect lengths.
5716   *
5717   * This function overrides the mbstring encoding to a binary-safe encoding, and
5718   * resets it to the users expected encoding afterwards through the
5719   * `reset_mbstring_encoding` function.
5720   *
5721   * It is safe to recursively call this function, however each
5722   * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
5723   * of `reset_mbstring_encoding()` calls.
5724   *
5725   * @since 3.7.0
5726   *
5727   * @see reset_mbstring_encoding()
5728   *
5729   * @staticvar array $encodings
5730   * @staticvar bool  $overloaded
5731   *
5732   * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
5733   *                    Default false.
5734   */
5735  function mbstring_binary_safe_encoding( $reset = false ) {
5736      static $encodings  = array();
5737      static $overloaded = null;
5738  
5739      if ( is_null( $overloaded ) ) {
5740          $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
5741      }
5742  
5743      if ( false === $overloaded ) {
5744          return;
5745      }
5746  
5747      if ( ! $reset ) {
5748          $encoding = mb_internal_encoding();
5749          array_push( $encodings, $encoding );
5750          mb_internal_encoding( 'ISO-8859-1' );
5751      }
5752  
5753      if ( $reset && $encodings ) {
5754          $encoding = array_pop( $encodings );
5755          mb_internal_encoding( $encoding );
5756      }
5757  }
5758  
5759  /**
5760   * Reset the mbstring internal encoding to a users previously set encoding.
5761   *
5762   * @see mbstring_binary_safe_encoding()
5763   *
5764   * @since 3.7.0
5765   */
5766  function reset_mbstring_encoding() {
5767      mbstring_binary_safe_encoding( true );
5768  }
5769  
5770  /**
5771   * Filter/validate a variable as a boolean.
5772   *
5773   * Alternative to `filter_var( $var, FILTER_VALIDATE_BOOLEAN )`.
5774   *
5775   * @since 4.0.0
5776   *
5777   * @param mixed $var Boolean value to validate.
5778   * @return bool Whether the value is validated.
5779   */
5780  function wp_validate_boolean( $var ) {
5781      if ( is_bool( $var ) ) {
5782          return $var;
5783      }
5784  
5785      if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
5786          return false;
5787      }
5788  
5789      return (bool) $var;
5790  }
5791  
5792  /**
5793   * Delete a file
5794   *
5795   * @since 4.2.0
5796   *
5797   * @param string $file The path to the file to delete.
5798   */
5799  function wp_delete_file( $file ) {
5800      /**
5801       * Filters the path of the file to delete.
5802       *
5803       * @since 2.1.0
5804       *
5805       * @param string $file Path to the file to delete.
5806       */
5807      $delete = apply_filters( 'wp_delete_file', $file );
5808      if ( ! empty( $delete ) ) {
5809          @unlink( $delete );
5810      }
5811  }
5812  
5813  /**
5814   * Outputs a small JS snippet on preview tabs/windows to remove `window.name` on unload.
5815   *
5816   * This prevents reusing the same tab for a preview when the user has navigated away.
5817   *
5818   * @since 4.3.0
5819   *
5820   * @global WP_Post $post
5821   */
5822  function wp_post_preview_js() {
5823      global $post;
5824  
5825      if ( ! is_preview() || empty( $post ) ) {
5826          return;
5827      }
5828  
5829      // Has to match the window name used in post_submit_meta_box()
5830      $name = 'wp-preview-' . (int) $post->ID;
5831  
5832      ?>
5833      <script>
5834      ( function() {
5835          var query = document.location.search;
5836  
5837          if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
5838              window.name = '<?php echo $name; ?>';
5839          }
5840  
5841          if ( window.addEventListener ) {
5842              window.addEventListener( 'unload', function() { window.name = ''; }, false );
5843          }
5844      }());
5845      </script>
5846      <?php
5847  }
5848  
5849  /**
5850   * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601/RFC3339.
5851   *
5852   * Explicitly strips timezones, as datetimes are not saved with any timezone
5853   * information. Including any information on the offset could be misleading.
5854   *
5855   * @since 4.4.0
5856   *
5857   * @param string $date_string Date string to parse and format.
5858   * @return string Date formatted for ISO8601/RFC3339.
5859   */
5860  function mysql_to_rfc3339( $date_string ) {
5861      $formatted = mysql2date( 'c', $date_string, false );
5862  
5863      // Strip timezone information
5864      return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted );
5865  }
5866  
5867  /**
5868   * Attempts to raise the PHP memory limit for memory intensive processes.
5869   *
5870   * Only allows raising the existing limit and prevents lowering it.
5871   *
5872   * @since 4.6.0
5873   *
5874   * @param string $context Optional. Context in which the function is called. Accepts either 'admin',
5875   *                        'image', or an arbitrary other context. If an arbitrary context is passed,
5876   *                        the similarly arbitrary {@see '{$context}_memory_limit'} filter will be
5877   *                        invoked. Default 'admin'.
5878   * @return bool|int|string The limit that was set or false on failure.
5879   */
5880  function wp_raise_memory_limit( $context = 'admin' ) {
5881      // Exit early if the limit cannot be changed.
5882      if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
5883          return false;
5884      }
5885  
5886      $current_limit     = @ini_get( 'memory_limit' );
5887      $current_limit_int = wp_convert_hr_to_bytes( $current_limit );
5888  
5889      if ( -1 === $current_limit_int ) {
5890          return false;
5891      }
5892  
5893      $wp_max_limit     = WP_MAX_MEMORY_LIMIT;
5894      $wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
5895      $filtered_limit   = $wp_max_limit;
5896  
5897      switch ( $context ) {
5898          case 'admin':
5899              /**
5900               * Filters the maximum memory limit available for administration screens.
5901               *
5902               * This only applies to administrators, who may require more memory for tasks
5903               * like updates. Memory limits when processing images (uploaded or edited by
5904               * users of any role) are handled separately.
5905               *
5906               * The `WP_MAX_MEMORY_LIMIT` constant specifically defines the maximum memory
5907               * limit available when in the administration back end. The default is 256M
5908               * (256 megabytes of memory) or the original `memory_limit` php.ini value if
5909               * this is higher.
5910               *
5911               * @since 3.0.0
5912               * @since 4.6.0 The default now takes the original `memory_limit` into account.
5913               *
5914               * @param int|string $filtered_limit The maximum WordPress memory limit. Accepts an integer
5915               *                                   (bytes), or a shorthand string notation, such as '256M'.
5916               */
5917              $filtered_limit = apply_filters( 'admin_memory_limit', $filtered_limit );
5918              break;
5919  
5920          case 'image':
5921              /**
5922               * Filters the memory limit allocated for image manipulation.
5923               *
5924               * @since 3.5.0
5925               * @since 4.6.0 The default now takes the origina