[ Index ]

PHP Cross Reference of WordPress

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