public/edition/wp-includes/functions.php line 6081

Open in your IDE?
  1. <?php
  2. /**
  3.  * Main WordPress API
  4.  *
  5.  * @package WordPress
  6.  */
  7. // Don't load directly.
  8. if ( ! defined'ABSPATH' ) ) {
  9.     die( '-1' );
  10. }
  11. require ABSPATH WPINC '/option.php';
  12. /**
  13.  * Converts given MySQL date string into a different format.
  14.  *
  15.  *  - `$format` should be a PHP date format string.
  16.  *  - 'U' and 'G' formats will return an integer sum of timestamp with timezone offset.
  17.  *  - `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`).
  18.  *
  19.  * Historically UTC time could be passed to the function to produce Unix timestamp.
  20.  *
  21.  * If `$translate` is true then the given date and format string will
  22.  * be passed to `wp_date()` for translation.
  23.  *
  24.  * @since 0.71
  25.  *
  26.  * @param string $format    Format of the date to return.
  27.  * @param string $date      Date string to convert.
  28.  * @param bool   $translate Whether the return date should be translated. Default true.
  29.  * @return string|int|false Integer if `$format` is 'U' or 'G', string otherwise.
  30.  *                          False on failure.
  31.  */
  32. function mysql2date$format$date$translate true ) {
  33.     if ( empty( $date ) ) {
  34.         return false;
  35.     }
  36.     $timezone wp_timezone();
  37.     $datetime date_create$date$timezone );
  38.     if ( false === $datetime ) {
  39.         return false;
  40.     }
  41.     // Returns a sum of timestamp with timezone offset. Ideally should never be used.
  42.     if ( 'G' === $format || 'U' === $format ) {
  43.         return $datetime->getTimestamp() + $datetime->getOffset();
  44.     }
  45.     if ( $translate ) {
  46.         return wp_date$format$datetime->getTimestamp(), $timezone );
  47.     }
  48.     return $datetime->format$format );
  49. }
  50. /**
  51.  * Retrieves the current time based on specified type.
  52.  *
  53.  *  - The 'mysql' type will return the time in the format for MySQL DATETIME field.
  54.  *  - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp
  55.  *    and timezone offset, depending on `$gmt`.
  56.  *  - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
  57.  *
  58.  * If `$gmt` is a truthy value then both types will use GMT time, otherwise the
  59.  * output is adjusted with the GMT offset for the site.
  60.  *
  61.  * @since 1.0.0
  62.  * @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned.
  63.  *
  64.  * @param string   $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U',
  65.  *                       or PHP date format string (e.g. 'Y-m-d').
  66.  * @param int|bool $gmt  Optional. Whether to use GMT timezone. Default false.
  67.  * @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise.
  68.  */
  69. function current_time$type$gmt ) {
  70.     // Don't use non-GMT timestamp, unless you know the difference and really need to.
  71.     if ( 'timestamp' === $type || 'U' === $type ) {
  72.         return $gmt time() : time() + (int) ( (float) get_option'gmt_offset' ) * HOUR_IN_SECONDS );
  73.     }
  74.     if ( 'mysql' === $type ) {
  75.         $type 'Y-m-d H:i:s';
  76.     }
  77.     $timezone $gmt ? new DateTimeZone'UTC' ) : wp_timezone();
  78.     $datetime = new DateTime'now'$timezone );
  79.     return $datetime->format$type );
  80. }
  81. /**
  82.  * Retrieves the current time as an object using the site's timezone.
  83.  *
  84.  * @since 5.3.0
  85.  *
  86.  * @return DateTimeImmutable Date and time object.
  87.  */
  88. function current_datetime() {
  89.     return new DateTimeImmutable'now'wp_timezone() );
  90. }
  91. /**
  92.  * Retrieves the timezone of the site as a string.
  93.  *
  94.  * Uses the `timezone_string` option to get a proper timezone name if available,
  95.  * otherwise falls back to a manual UTC ± offset.
  96.  *
  97.  * Example return values:
  98.  *
  99.  *  - 'Europe/Rome'
  100.  *  - 'America/North_Dakota/New_Salem'
  101.  *  - 'UTC'
  102.  *  - '-06:30'
  103.  *  - '+00:00'
  104.  *  - '+08:45'
  105.  *
  106.  * @since 5.3.0
  107.  *
  108.  * @return string PHP timezone name or a ±HH:MM offset.
  109.  */
  110. function wp_timezone_string() {
  111.     $timezone_string get_option'timezone_string' );
  112.     if ( $timezone_string ) {
  113.         return $timezone_string;
  114.     }
  115.     $offset  = (float) get_option'gmt_offset' );
  116.     $hours   = (int) $offset;
  117.     $minutes = ( $offset $hours );
  118.     $sign      = ( $offset ) ? '-' '+';
  119.     $abs_hour  abs$hours );
  120.     $abs_mins  abs$minutes 60 );
  121.     $tz_offset sprintf'%s%02d:%02d'$sign$abs_hour$abs_mins );
  122.     return $tz_offset;
  123. }
  124. /**
  125.  * Retrieves the timezone of the site as a `DateTimeZone` object.
  126.  *
  127.  * Timezone can be based on a PHP timezone string or a ±HH:MM offset.
  128.  *
  129.  * @since 5.3.0
  130.  *
  131.  * @return DateTimeZone Timezone object.
  132.  */
  133. function wp_timezone() {
  134.     return new DateTimeZonewp_timezone_string() );
  135. }
  136. /**
  137.  * Retrieves the date in localized format, based on a sum of Unix timestamp and
  138.  * timezone offset in seconds.
  139.  *
  140.  * If the locale specifies the locale month and weekday, then the locale will
  141.  * take over the format for the date. If it isn't, then the date format string
  142.  * will be used instead.
  143.  *
  144.  * Note that due to the way WP typically generates a sum of timestamp and offset
  145.  * with `strtotime()`, it implies offset added at a _current_ time, not at the time
  146.  * the timestamp represents. Storing such timestamps or calculating them differently
  147.  * will lead to invalid output.
  148.  *
  149.  * @since 0.71
  150.  * @since 5.3.0 Converted into a wrapper for wp_date().
  151.  *
  152.  * @param string   $format                Format to display the date.
  153.  * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset
  154.  *                                        in seconds. Default false.
  155.  * @param bool     $gmt                   Optional. Whether to use GMT timezone. Only applies
  156.  *                                        if timestamp is not provided. Default false.
  157.  * @return string The date, translated if locale specifies it.
  158.  */
  159. function date_i18n$format$timestamp_with_offset false$gmt false ) {
  160.     $timestamp $timestamp_with_offset;
  161.     // If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true).
  162.     if ( ! is_numeric$timestamp ) ) {
  163.         // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
  164.         $timestamp current_time'timestamp'$gmt );
  165.     }
  166.     /*
  167.      * This is a legacy implementation quirk that the returned timestamp is also with offset.
  168.      * Ideally this function should never be used to produce a timestamp.
  169.      */
  170.     if ( 'U' === $format ) {
  171.         $date $timestamp;
  172.     } elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC.
  173.         $date wp_date$formatnull, new DateTimeZone'UTC' ) );
  174.     } elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone.
  175.         $date wp_date$format );
  176.     } else {
  177.         /*
  178.          * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone.
  179.          * This is the best attempt to reverse that operation into a local time to use.
  180.          */
  181.         $local_time gmdate'Y-m-d H:i:s'$timestamp );
  182.         $timezone   wp_timezone();
  183.         $datetime   date_create$local_time$timezone );
  184.         $date       wp_date$format$datetime->getTimestamp(), $timezone );
  185.     }
  186.     /**
  187.      * Filters the date formatted based on the locale.
  188.      *
  189.      * @since 2.8.0
  190.      *
  191.      * @param string $date      Formatted date string.
  192.      * @param string $format    Format to display the date.
  193.      * @param int    $timestamp A sum of Unix timestamp and timezone offset in seconds.
  194.      *                          Might be without offset if input omitted timestamp but requested GMT.
  195.      * @param bool   $gmt       Whether to use GMT timezone. Only applies if timestamp was not provided.
  196.      *                          Default false.
  197.      */
  198.     $date apply_filters'date_i18n'$date$format$timestamp$gmt );
  199.     return $date;
  200. }
  201. /**
  202.  * Retrieves the date, in localized format.
  203.  *
  204.  * This is a newer function, intended to replace `date_i18n()` without legacy quirks in it.
  205.  *
  206.  * Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed
  207.  * with timezone offset.
  208.  *
  209.  * @since 5.3.0
  210.  *
  211.  * @global WP_Locale $wp_locale WordPress date and time locale object.
  212.  *
  213.  * @param string       $format    PHP date format.
  214.  * @param int          $timestamp Optional. Unix timestamp. Defaults to current time.
  215.  * @param DateTimeZone $timezone  Optional. Timezone to output result in. Defaults to timezone
  216.  *                                from site settings.
  217.  * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
  218.  */
  219. function wp_date$format$timestamp null$timezone null ) {
  220.     global $wp_locale;
  221.     if ( null === $timestamp ) {
  222.         $timestamp time();
  223.     } elseif ( ! is_numeric$timestamp ) ) {
  224.         return false;
  225.     }
  226.     if ( ! $timezone ) {
  227.         $timezone wp_timezone();
  228.     }
  229.     $datetime date_create'@' $timestamp );
  230.     $datetime->setTimezone$timezone );
  231.     if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) {
  232.         $date $datetime->format$format );
  233.     } else {
  234.         // We need to unpack shorthand `r` format because it has parts that might be localized.
  235.         $format preg_replace'/(?<!\\\\)r/'DATE_RFC2822$format );
  236.         $new_format    '';
  237.         $format_length strlen$format );
  238.         $month         $wp_locale->get_month$datetime->format'm' ) );
  239.         $weekday       $wp_locale->get_weekday$datetime->format'w' ) );
  240.         for ( $i 0$i $format_length$i++ ) {
  241.             switch ( $format$i ] ) {
  242.                 case 'D':
  243.                     $new_format .= addcslashes$wp_locale->get_weekday_abbrev$weekday ), '\\A..Za..z' );
  244.                     break;
  245.                 case 'F':
  246.                     $new_format .= addcslashes$month'\\A..Za..z' );
  247.                     break;
  248.                 case 'l':
  249.                     $new_format .= addcslashes$weekday'\\A..Za..z' );
  250.                     break;
  251.                 case 'M':
  252.                     $new_format .= addcslashes$wp_locale->get_month_abbrev$month ), '\\A..Za..z' );
  253.                     break;
  254.                 case 'a':
  255.                     $new_format .= addcslashes$wp_locale->get_meridiem$datetime->format'a' ) ), '\\A..Za..z' );
  256.                     break;
  257.                 case 'A':
  258.                     $new_format .= addcslashes$wp_locale->get_meridiem$datetime->format'A' ) ), '\\A..Za..z' );
  259.                     break;
  260.                 case '\\':
  261.                     $new_format .= $format$i ];
  262.                     // If character follows a slash, we add it without translating.
  263.                     if ( $i $format_length ) {
  264.                         $new_format .= $format[ ++$i ];
  265.                     }
  266.                     break;
  267.                 default:
  268.                     $new_format .= $format$i ];
  269.                     break;
  270.             }
  271.         }
  272.         $date $datetime->format$new_format );
  273.         $date wp_maybe_decline_date$date$format );
  274.     }
  275.     /**
  276.      * Filters the date formatted based on the locale.
  277.      *
  278.      * @since 5.3.0
  279.      *
  280.      * @param string       $date      Formatted date string.
  281.      * @param string       $format    Format to display the date.
  282.      * @param int          $timestamp Unix timestamp.
  283.      * @param DateTimeZone $timezone  Timezone.
  284.      */
  285.     $date apply_filters'wp_date'$date$format$timestamp$timezone );
  286.     return $date;
  287. }
  288. /**
  289.  * Determines if the date should be declined.
  290.  *
  291.  * If the locale specifies that month names require a genitive case in certain
  292.  * formats (like 'j F Y'), the month name will be replaced with a correct form.
  293.  *
  294.  * @since 4.4.0
  295.  * @since 5.4.0 The `$format` parameter was added.
  296.  *
  297.  * @global WP_Locale $wp_locale WordPress date and time locale object.
  298.  *
  299.  * @param string $date   Formatted date string.
  300.  * @param string $format Optional. Date format to check. Default empty string.
  301.  * @return string The date, declined if locale specifies it.
  302.  */
  303. function wp_maybe_decline_date$date$format '' ) {
  304.     global $wp_locale;
  305.     // i18n functions are not available in SHORTINIT mode.
  306.     if ( ! function_exists'_x' ) ) {
  307.         return $date;
  308.     }
  309.     /*
  310.      * translators: If months in your language require a genitive case,
  311.      * translate this to 'on'. Do not translate into your own language.
  312.      */
  313.     if ( 'on' === _x'off''decline months names: on or off' ) ) {
  314.         $months          $wp_locale->month;
  315.         $months_genitive $wp_locale->month_genitive;
  316.         /*
  317.          * Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name)
  318.          * and decline the month.
  319.          */
  320.         if ( $format ) {
  321.             $decline preg_match'#[dj]\.? F#'$format );
  322.         } else {
  323.             // If the format is not passed, try to guess it from the date string.
  324.             $decline preg_match'#\b\d{1,2}\.? [^\d ]+\b#u'$date );
  325.         }
  326.         if ( $decline ) {
  327.             foreach ( $months as $key => $month ) {
  328.                 $months$key ] = '# ' preg_quote$month'#' ) . '\b#u';
  329.             }
  330.             foreach ( $months_genitive as $key => $month ) {
  331.                 $months_genitive$key ] = ' ' $month;
  332.             }
  333.             $date preg_replace$months$months_genitive$date );
  334.         }
  335.         /*
  336.          * Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix)
  337.          * and change it to declined 'j F'.
  338.          */
  339.         if ( $format ) {
  340.             $decline preg_match'#F [dj]#'$format );
  341.         } else {
  342.             // If the format is not passed, try to guess it from the date string.
  343.             $decline preg_match'#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u'trim$date ) );
  344.         }
  345.         if ( $decline ) {
  346.             foreach ( $months as $key => $month ) {
  347.                 $months$key ] = '#\b' preg_quote$month'#' ) . ' (\d{1,2})(st|nd|rd|th)?([-–]\d{1,2})?(st|nd|rd|th)?\b#u';
  348.             }
  349.             foreach ( $months_genitive as $key => $month ) {
  350.                 $months_genitive$key ] = '$1$3 ' $month;
  351.             }
  352.             $date preg_replace$months$months_genitive$date );
  353.         }
  354.     }
  355.     // Used for locale-specific rules.
  356.     $locale get_locale();
  357.     if ( 'ca' === $locale ) {
  358.         // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
  359.         $date preg_replace'# de ([ao])#i'" d'\\1"$date );
  360.     }
  361.     return $date;
  362. }
  363. /**
  364.  * Converts float number to format based on the locale.
  365.  *
  366.  * @since 2.3.0
  367.  *
  368.  * @global WP_Locale $wp_locale WordPress date and time locale object.
  369.  *
  370.  * @param float $number   The number to convert based on locale.
  371.  * @param int   $decimals Optional. Precision of the number of decimal places. Default 0.
  372.  * @return string Converted number in string format.
  373.  */
  374. function number_format_i18n$number$decimals ) {
  375.     global $wp_locale;
  376.     if ( isset( $wp_locale ) ) {
  377.         $formatted number_format$numberabsint$decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
  378.     } else {
  379.         $formatted number_format$numberabsint$decimals ) );
  380.     }
  381.     /**
  382.      * Filters the number formatted based on the locale.
  383.      *
  384.      * @since 2.8.0
  385.      * @since 4.9.0 The `$number` and `$decimals` parameters were added.
  386.      *
  387.      * @param string $formatted Converted number in string format.
  388.      * @param float  $number    The number to convert based on locale.
  389.      * @param int    $decimals  Precision of the number of decimal places.
  390.      */
  391.     return apply_filters'number_format_i18n'$formatted$number$decimals );
  392. }
  393. /**
  394.  * Converts a number of bytes to the largest unit the bytes will fit into.
  395.  *
  396.  * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
  397.  * number of bytes to human readable number by taking the number of that unit
  398.  * that the bytes will go into it. Supports YB value.
  399.  *
  400.  * Please note that integers in PHP are limited to 32 bits, unless they are on
  401.  * 64 bit architecture, then they have 64 bit size. If you need to place the
  402.  * larger size then what PHP integer type will hold, then use a string. It will
  403.  * be converted to a double, which should always have 64 bit length.
  404.  *
  405.  * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
  406.  *
  407.  * @since 2.3.0
  408.  * @since 6.0.0 Support for PB, EB, ZB, and YB was added.
  409.  *
  410.  * @param int|string $bytes    Number of bytes. Note max integer size for integers.
  411.  * @param int        $decimals Optional. Precision of number of decimal places. Default 0.
  412.  * @return string|false Number string on success, false on failure.
  413.  */
  414. function size_format$bytes$decimals ) {
  415.     $quant = array(
  416.         /* translators: Unit symbol for yottabyte. */
  417.         _x'YB''unit symbol' ) => YB_IN_BYTES,
  418.         /* translators: Unit symbol for zettabyte. */
  419.         _x'ZB''unit symbol' ) => ZB_IN_BYTES,
  420.         /* translators: Unit symbol for exabyte. */
  421.         _x'EB''unit symbol' ) => EB_IN_BYTES,
  422.         /* translators: Unit symbol for petabyte. */
  423.         _x'PB''unit symbol' ) => PB_IN_BYTES,
  424.         /* translators: Unit symbol for terabyte. */
  425.         _x'TB''unit symbol' ) => TB_IN_BYTES,
  426.         /* translators: Unit symbol for gigabyte. */
  427.         _x'GB''unit symbol' ) => GB_IN_BYTES,
  428.         /* translators: Unit symbol for megabyte. */
  429.         _x'MB''unit symbol' ) => MB_IN_BYTES,
  430.         /* translators: Unit symbol for kilobyte. */
  431.         _x'KB''unit symbol' ) => KB_IN_BYTES,
  432.         /* translators: Unit symbol for byte. */
  433.         _x'B''unit symbol' )  => 1,
  434.     );
  435.     if ( === $bytes ) {
  436.         /* translators: Unit symbol for byte. */
  437.         return number_format_i18n0$decimals ) . ' ' _x'B''unit symbol' );
  438.     }
  439.     foreach ( $quant as $unit => $mag ) {
  440.         if ( (float) $bytes >= $mag ) {
  441.             return number_format_i18n$bytes $mag$decimals ) . ' ' $unit;
  442.         }
  443.     }
  444.     return false;
  445. }
  446. /**
  447.  * Converts a duration to human readable format.
  448.  *
  449.  * @since 5.1.0
  450.  *
  451.  * @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
  452.  *                         with a possible prepended negative sign (-).
  453.  * @return string|false A human readable duration string, false on failure.
  454.  */
  455. function human_readable_duration$duration '' ) {
  456.     if ( ( empty( $duration ) || ! is_string$duration ) ) ) {
  457.         return false;
  458.     }
  459.     $duration trim$duration );
  460.     // Remove prepended negative sign.
  461.     if ( str_starts_with$duration'-' ) ) {
  462.         $duration substr$duration);
  463.     }
  464.     // Extract duration parts.
  465.     $duration_parts array_reverseexplode':'$duration ) );
  466.     $duration_count count$duration_parts );
  467.     $hour   null;
  468.     $minute null;
  469.     $second null;
  470.     if ( === $duration_count ) {
  471.         // Validate HH:ii:ss duration format.
  472.         if ( ! ( (bool) preg_match'/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/'$duration ) ) ) {
  473.             return false;
  474.         }
  475.         // Three parts: hours, minutes & seconds.
  476.         list( $second$minute$hour ) = $duration_parts;
  477.     } elseif ( === $duration_count ) {
  478.         // Validate ii:ss duration format.
  479.         if ( ! ( (bool) preg_match'/^([0-5]?[0-9]):([0-5]?[0-9])$/'$duration ) ) ) {
  480.             return false;
  481.         }
  482.         // Two parts: minutes & seconds.
  483.         list( $second$minute ) = $duration_parts;
  484.     } else {
  485.         return false;
  486.     }
  487.     $human_readable_duration = array();
  488.     // Add the hour part to the string.
  489.     if ( is_numeric$hour ) ) {
  490.         /* translators: %s: Time duration in hour or hours. */
  491.         $human_readable_duration[] = sprintf_n'%s hour''%s hours'$hour ), (int) $hour );
  492.     }
  493.     // Add the minute part to the string.
  494.     if ( is_numeric$minute ) ) {
  495.         /* translators: %s: Time duration in minute or minutes. */
  496.         $human_readable_duration[] = sprintf_n'%s minute''%s minutes'$minute ), (int) $minute );
  497.     }
  498.     // Add the second part to the string.
  499.     if ( is_numeric$second ) ) {
  500.         /* translators: %s: Time duration in second or seconds. */
  501.         $human_readable_duration[] = sprintf_n'%s second''%s seconds'$second ), (int) $second );
  502.     }
  503.     return implode', '$human_readable_duration );
  504. }
  505. /**
  506.  * Gets the week start and end from the datetime or date string from MySQL.
  507.  *
  508.  * @since 0.71
  509.  *
  510.  * @param string     $mysqlstring   Date or datetime field type from MySQL.
  511.  * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
  512.  * @return int[] {
  513.  *     Week start and end dates as Unix timestamps.
  514.  *
  515.  *     @type int $start The week start date as a Unix timestamp.
  516.  *     @type int $end   The week end date as a Unix timestamp.
  517.  * }
  518.  */
  519. function get_weekstartend$mysqlstring$start_of_week '' ) {
  520.     // MySQL string year.
  521.     $my substr$mysqlstring0);
  522.     // MySQL string month.
  523.     $mm substr$mysqlstring8);
  524.     // MySQL string day.
  525.     $md substr$mysqlstring5);
  526.     // The timestamp for MySQL string day.
  527.     $day mktime000$md$mm$my );
  528.     // The day of the week from the timestamp.
  529.     $weekday = (int) gmdate'w'$day );
  530.     if ( ! is_numeric$start_of_week ) ) {
  531.         $start_of_week = (int) get_option'start_of_week' );
  532.     }
  533.     if ( $weekday $start_of_week ) {
  534.         $weekday += 7;
  535.     }
  536.     // The most recent week start day on or before $day.
  537.     $start $day DAY_IN_SECONDS * ( $weekday $start_of_week );
  538.     // $start + 1 week - 1 second.
  539.     $end $start WEEK_IN_SECONDS 1;
  540.     return compact'start''end' );
  541. }
  542. /**
  543.  * Serializes data, if needed.
  544.  *
  545.  * @since 2.0.5
  546.  *
  547.  * @param string|array|object $data Data that might be serialized.
  548.  * @return mixed A scalar data.
  549.  */
  550. function maybe_serialize$data ) {
  551.     if ( is_array$data ) || is_object$data ) ) {
  552.         return serialize$data );
  553.     }
  554.     /*
  555.      * Double serialization is required for backward compatibility.
  556.      * See https://core.trac.wordpress.org/ticket/12930
  557.      * Also the world will end. See WP 3.6.1.
  558.      */
  559.     if ( is_serialized$datafalse ) ) {
  560.         return serialize$data );
  561.     }
  562.     return $data;
  563. }
  564. /**
  565.  * Unserializes data only if it was serialized.
  566.  *
  567.  * @since 2.0.0
  568.  *
  569.  * @param string $data Data that might be unserialized.
  570.  * @return mixed Unserialized data can be any type.
  571.  */
  572. function maybe_unserialize$data ) {
  573.     if ( is_serialized$data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
  574.         return @unserializetrim$data ) );
  575.     }
  576.     return $data;
  577. }
  578. /**
  579.  * Checks value to find if it was serialized.
  580.  *
  581.  * If $data is not a string, then returned value will always be false.
  582.  * Serialized data is always a string.
  583.  *
  584.  * @since 2.0.5
  585.  * @since 6.1.0 Added Enum support.
  586.  *
  587.  * @param string $data   Value to check to see if was serialized.
  588.  * @param bool   $strict Optional. Whether to be strict about the end of the string. Default true.
  589.  * @return bool False if not serialized and true if it was.
  590.  */
  591. function is_serialized$data$strict true ) {
  592.     // If it isn't a string, it isn't serialized.
  593.     if ( ! is_string$data ) ) {
  594.         return false;
  595.     }
  596.     $data trim$data );
  597.     if ( 'N;' === $data ) {
  598.         return true;
  599.     }
  600.     if ( strlen$data ) < ) {
  601.         return false;
  602.     }
  603.     if ( ':' !== $data[1] ) {
  604.         return false;
  605.     }
  606.     if ( $strict ) {
  607.         $lastc substr$data, -);
  608.         if ( ';' !== $lastc && '}' !== $lastc ) {
  609.             return false;
  610.         }
  611.     } else {
  612.         $semicolon strpos$data';' );
  613.         $brace     strpos$data'}' );
  614.         // Either ; or } must exist.
  615.         if ( false === $semicolon && false === $brace ) {
  616.             return false;
  617.         }
  618.         // But neither must be in the first X characters.
  619.         if ( false !== $semicolon && $semicolon ) {
  620.             return false;
  621.         }
  622.         if ( false !== $brace && $brace ) {
  623.             return false;
  624.         }
  625.     }
  626.     $token $data[0];
  627.     switch ( $token ) {
  628.         case 's':
  629.             if ( $strict ) {
  630.                 if ( '"' !== substr$data, -2) ) {
  631.                     return false;
  632.                 }
  633.             } elseif ( ! str_contains$data'"' ) ) {
  634.                 return false;
  635.             }
  636.             // Or else fall through.
  637.         case 'a':
  638.         case 'O':
  639.         case 'E':
  640.             return (bool) preg_match"/^{$token}:[0-9]+:/s"$data );
  641.         case 'b':
  642.         case 'i':
  643.         case 'd':
  644.             $end $strict '$' '';
  645.             return (bool) preg_match"/^{$token}:[0-9.E+-]+;$end/"$data );
  646.     }
  647.     return false;
  648. }
  649. /**
  650.  * Checks whether serialized data is of string type.
  651.  *
  652.  * @since 2.0.5
  653.  *
  654.  * @param string $data Serialized data.
  655.  * @return bool False if not a serialized string, true if it is.
  656.  */
  657. function is_serialized_string$data ) {
  658.     // if it isn't a string, it isn't a serialized string.
  659.     if ( ! is_string$data ) ) {
  660.         return false;
  661.     }
  662.     $data trim$data );
  663.     if ( strlen$data ) < ) {
  664.         return false;
  665.     } elseif ( ':' !== $data[1] ) {
  666.         return false;
  667.     } elseif ( ! str_ends_with$data';' ) ) {
  668.         return false;
  669.     } elseif ( 's' !== $data[0] ) {
  670.         return false;
  671.     } elseif ( '"' !== substr$data, -2) ) {
  672.         return false;
  673.     } else {
  674.         return true;
  675.     }
  676. }
  677. /**
  678.  * Retrieves post title from XMLRPC XML.
  679.  *
  680.  * If the title element is not part of the XML, then the default post title from
  681.  * the $post_default_title will be used instead.
  682.  *
  683.  * @since 0.71
  684.  *
  685.  * @global string $post_default_title Default XML-RPC post title.
  686.  *
  687.  * @param string $content XMLRPC XML Request content
  688.  * @return string Post title
  689.  */
  690. function xmlrpc_getposttitle$content ) {
  691.     global $post_default_title;
  692.     if ( preg_match'/<title>(.+?)<\/title>/is'$content$matchtitle ) ) {
  693.         $post_title $matchtitle[1];
  694.     } else {
  695.         $post_title $post_default_title;
  696.     }
  697.     return $post_title;
  698. }
  699. /**
  700.  * Retrieves the post category or categories from XMLRPC XML.
  701.  *
  702.  * If the category element is not found, then the default post category will be
  703.  * used. The return type then would be what $post_default_category. If the
  704.  * category is found, then it will always be an array.
  705.  *
  706.  * @since 0.71
  707.  *
  708.  * @global string $post_default_category Default XML-RPC post category.
  709.  *
  710.  * @param string $content XMLRPC XML Request content
  711.  * @return string|array List of categories or category name.
  712.  */
  713. function xmlrpc_getpostcategory$content ) {
  714.     global $post_default_category;
  715.     if ( preg_match'/<category>(.+?)<\/category>/is'$content$matchcat ) ) {
  716.         $post_category trim$matchcat[1], ',' );
  717.         $post_category explode','$post_category );
  718.     } else {
  719.         $post_category $post_default_category;
  720.     }
  721.     return $post_category;
  722. }
  723. /**
  724.  * XMLRPC XML content without title and category elements.
  725.  *
  726.  * @since 0.71
  727.  *
  728.  * @param string $content XML-RPC XML Request content.
  729.  * @return string XMLRPC XML Request content without title and category elements.
  730.  */
  731. function xmlrpc_removepostdata$content ) {
  732.     $content preg_replace'/<title>(.+?)<\/title>/si'''$content );
  733.     $content preg_replace'/<category>(.+?)<\/category>/si'''$content );
  734.     $content trim$content );
  735.     return $content;
  736. }
  737. /**
  738.  * Uses RegEx to extract URLs from arbitrary content.
  739.  *
  740.  * @since 3.7.0
  741.  * @since 6.0.0 Fixes support for HTML entities (Trac 30580).
  742.  *
  743.  * @param string $content Content to extract URLs from.
  744.  * @return string[] Array of URLs found in passed string.
  745.  */
  746. function wp_extract_urls$content ) {
  747.     preg_match_all(
  748.         "#([\"']?)("
  749.             '(?:([\w-]+:)?//?)'
  750.             '[^\s()<>]+'
  751.             '[.]'
  752.             '(?:'
  753.                 '\([\w\d]+\)|'
  754.                 '(?:'
  755.                     "[^`!()\[\]{}:'\".,<>«»“”‘’\s]|"
  756.                     '(?:[:]\d+)?/?'
  757.                 ')+'
  758.             ')'
  759.         ")\\1#",
  760.         $content,
  761.         $post_links
  762.     );
  763.     $post_links array_unique(
  764.         array_map(
  765.             static function ( $link ) {
  766.                 // Decode to replace valid entities, like &amp;.
  767.                 $link html_entity_decode$link );
  768.                 // Maintain backward compatibility by removing extraneous semi-colons (`;`).
  769.                 return str_replace';'''$link );
  770.             },
  771.             $post_links[2]
  772.         )
  773.     );
  774.     return array_values$post_links );
  775. }
  776. /**
  777.  * Checks content for video and audio links to add as enclosures.
  778.  *
  779.  * Will not add enclosures that have already been added and will
  780.  * remove enclosures that are no longer in the post. This is called as
  781.  * pingbacks and trackbacks.
  782.  *
  783.  * @since 1.5.0
  784.  * @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
  785.  *              updated to accept a post ID or a WP_Post object.
  786.  * @since 5.6.0 The `$content` parameter is no longer optional, but passing `null` to skip it
  787.  *              is still supported.
  788.  *
  789.  * @global wpdb $wpdb WordPress database abstraction object.
  790.  *
  791.  * @param string|null $content Post content. If `null`, the `post_content` field from `$post` is used.
  792.  * @param int|WP_Post $post    Post ID or post object.
  793.  * @return void|false Void on success, false if the post is not found.
  794.  */
  795. function do_enclose$content$post ) {
  796.     global $wpdb;
  797.     // @todo Tidy this code and make the debug code optional.
  798.     require_once ABSPATH WPINC '/class-IXR.php';
  799.     $post get_post$post );
  800.     if ( ! $post ) {
  801.         return false;
  802.     }
  803.     if ( null === $content ) {
  804.         $content $post->post_content;
  805.     }
  806.     $post_links = array();
  807.     $pung get_enclosed$post->ID );
  808.     $post_links_temp wp_extract_urls$content );
  809.     foreach ( $pung as $link_test ) {
  810.         // Link is no longer in post.
  811.         if ( ! in_array$link_test$post_links_temptrue ) ) {
  812.             $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 ) . '%' ) );
  813.             foreach ( $mids as $mid ) {
  814.                 delete_metadata_by_mid'post'$mid );
  815.             }
  816.         }
  817.     }
  818.     foreach ( (array) $post_links_temp as $link_test ) {
  819.         // If we haven't pung it already.
  820.         if ( ! in_array$link_test$pungtrue ) ) {
  821.             $test parse_url$link_test );
  822.             if ( false === $test ) {
  823.                 continue;
  824.             }
  825.             if ( isset( $test['query'] ) ) {
  826.                 $post_links[] = $link_test;
  827.             } elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
  828.                 $post_links[] = $link_test;
  829.             }
  830.         }
  831.     }
  832.     /**
  833.      * Filters the list of enclosure links before querying the database.
  834.      *
  835.      * Allows for the addition and/or removal of potential enclosures to save
  836.      * to postmeta before checking the database for existing enclosures.
  837.      *
  838.      * @since 4.4.0
  839.      *
  840.      * @param string[] $post_links An array of enclosure links.
  841.      * @param int      $post_id    Post ID.
  842.      */
  843.     $post_links apply_filters'enclosure_links'$post_links$post->ID );
  844.     foreach ( (array) $post_links as $url ) {
  845.         $url strip_fragment_from_url$url );
  846.         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 ) . '%' ) ) ) {
  847.             $headers wp_get_http_headers$url );
  848.             if ( $headers ) {
  849.                 $len           = isset( $headers['Content-Length'] ) ? (int) $headers['Content-Length'] : 0;
  850.                 $type          = isset( $headers['Content-Type'] ) ? $headers['Content-Type'] : '';
  851.                 $allowed_types = array( 'video''audio' );
  852.                 // Check to see if we can figure out the mime type from the extension.
  853.                 $url_parts parse_url$url );
  854.                 if ( false !== $url_parts && ! empty( $url_parts['path'] ) ) {
  855.                     $extension pathinfo$url_parts['path'], PATHINFO_EXTENSION );
  856.                     if ( ! empty( $extension ) ) {
  857.                         foreach ( wp_get_mime_types() as $exts => $mime ) {
  858.                             if ( preg_match'!^(' $exts ')$!i'$extension ) ) {
  859.                                 $type $mime;
  860.                                 break;
  861.                             }
  862.                         }
  863.                     }
  864.                 }
  865.                 if ( in_arraysubstr$type0strpos$type'/' ) ), $allowed_typestrue ) ) {
  866.                     add_post_meta$post->ID'enclosure'"$url\n$len\n$mime\n" );
  867.                 }
  868.             }
  869.         }
  870.     }
  871. }
  872. /**
  873.  * Retrieves HTTP Headers from URL.
  874.  *
  875.  * @since 1.5.1
  876.  *
  877.  * @param string $url        URL to retrieve HTTP headers from.
  878.  * @param bool   $deprecated Not Used.
  879.  * @return \WpOrg\Requests\Utility\CaseInsensitiveDictionary|false Headers on success, false on failure.
  880.  */
  881. function wp_get_http_headers$url$deprecated false ) {
  882.     if ( ! empty( $deprecated ) ) {
  883.         _deprecated_argument__FUNCTION__'2.7.0' );
  884.     }
  885.     $response wp_safe_remote_head$url );
  886.     if ( is_wp_error$response ) ) {
  887.         return false;
  888.     }
  889.     return wp_remote_retrieve_headers$response );
  890. }
  891. /**
  892.  * Determines whether the publish date of the current post in the loop is different
  893.  * from the publish date of the previous post in the loop.
  894.  *
  895.  * For more information on this and similar theme functions, check out
  896.  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  897.  * Conditional Tags} article in the Theme Developer Handbook.
  898.  *
  899.  * @since 0.71
  900.  *
  901.  * @global string $currentday  The day of the current post in the loop.
  902.  * @global string $previousday The day of the previous post in the loop.
  903.  *
  904.  * @return int 1 when new day, 0 if not a new day.
  905.  */
  906. function is_new_day() {
  907.     global $currentday$previousday;
  908.     if ( $currentday !== $previousday ) {
  909.         return 1;
  910.     } else {
  911.         return 0;
  912.     }
  913. }
  914. /**
  915.  * Builds URL query based on an associative and, or indexed array.
  916.  *
  917.  * This is a convenient function for easily building url queries. It sets the
  918.  * separator to '&' and uses _http_build_query() function.
  919.  *
  920.  * @since 2.3.0
  921.  *
  922.  * @see _http_build_query() Used to build the query
  923.  * @link https://www.php.net/manual/en/function.http-build-query.php for more on what
  924.  *       http_build_query() does.
  925.  *
  926.  * @param array $data URL-encode key/value pairs.
  927.  * @return string URL-encoded string.
  928.  */
  929. function build_query$data ) {
  930.     return _http_build_query$datanull'&'''false );
  931. }
  932. /**
  933.  * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
  934.  *
  935.  * @since 3.2.0
  936.  * @access private
  937.  *
  938.  * @see https://www.php.net/manual/en/function.http-build-query.php
  939.  *
  940.  * @param array|object $data      An array or object of data. Converted to array.
  941.  * @param string       $prefix    Optional. Numeric index. If set, start parameter numbering with it.
  942.  *                                Default null.
  943.  * @param string       $sep       Optional. Argument separator; defaults to 'arg_separator.output'.
  944.  *                                Default null.
  945.  * @param string       $key       Optional. Used to prefix key name. Default empty string.
  946.  * @param bool         $urlencode Optional. Whether to use urlencode() in the result. Default true.
  947.  * @return string The query string.
  948.  */
  949. function _http_build_query$data$prefix null$sep null$key ''$urlencode true ) {
  950.     $ret = array();
  951.     foreach ( (array) $data as $k => $v ) {
  952.         if ( $urlencode ) {
  953.             $k urlencode$k );
  954.         }
  955.         if ( is_int$k ) && null !== $prefix ) {
  956.             $k $prefix $k;
  957.         }
  958.         if ( ! empty( $key ) ) {
  959.             $k $key '%5B' $k '%5D';
  960.         }
  961.         if ( null === $v ) {
  962.             continue;
  963.         } elseif ( false === $v ) {
  964.             $v '0';
  965.         }
  966.         if ( is_array$v ) || is_object$v ) ) {
  967.             array_push$ret_http_build_query$v''$sep$k$urlencode ) );
  968.         } elseif ( $urlencode ) {
  969.             array_push$ret$k '=' urlencode$v ) );
  970.         } else {
  971.             array_push$ret$k '=' $v );
  972.         }
  973.     }
  974.     if ( null === $sep ) {
  975.         $sep ini_get'arg_separator.output' );
  976.     }
  977.     return implode$sep$ret );
  978. }
  979. /**
  980.  * Retrieves a modified URL query string.
  981.  *
  982.  * You can rebuild the URL and append query variables to the URL query by using this function.
  983.  * There are two ways to use this function; either a single key and value, or an associative array.
  984.  *
  985.  * Using a single key and value:
  986.  *
  987.  *     add_query_arg( 'key', 'value', 'http://example.com' );
  988.  *
  989.  * Using an associative array:
  990.  *
  991.  *     add_query_arg( array(
  992.  *         'key1' => 'value1',
  993.  *         'key2' => 'value2',
  994.  *     ), 'http://example.com' );
  995.  *
  996.  * Omitting the URL from either use results in the current URL being used
  997.  * (the value of `$_SERVER['REQUEST_URI']`).
  998.  *
  999.  * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
  1000.  *
  1001.  * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
  1002.  *
  1003.  * Important: The return value of add_query_arg() is not escaped by default. Output should be
  1004.  * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
  1005.  * (XSS) attacks.
  1006.  *
  1007.  * @since 1.5.0
  1008.  * @since 5.3.0 Formalized the existing and already documented parameters
  1009.  *              by adding `...$args` to the function signature.
  1010.  *
  1011.  * @param string|array $key   Either a query variable key, or an associative array of query variables.
  1012.  * @param string       $value Optional. Either a query variable value, or a URL to act upon.
  1013.  * @param string       $url   Optional. A URL to act upon.
  1014.  * @return string New URL query string (unescaped).
  1015.  */
  1016. function add_query_arg( ...$args ) {
  1017.     if ( is_array$args[0] ) ) {
  1018.         if ( count$args ) < || false === $args[1] ) {
  1019.             $uri $_SERVER['REQUEST_URI'];
  1020.         } else {
  1021.             $uri $args[1];
  1022.         }
  1023.     } else {
  1024.         if ( count$args ) < || false === $args[2] ) {
  1025.             $uri $_SERVER['REQUEST_URI'];
  1026.         } else {
  1027.             $uri $args[2];
  1028.         }
  1029.     }
  1030.     $frag strstr$uri'#' );
  1031.     if ( $frag ) {
  1032.         $uri substr$uri0, -strlen$frag ) );
  1033.     } else {
  1034.         $frag '';
  1035.     }
  1036.     if ( === stripos$uri'http://' ) ) {
  1037.         $protocol 'http://';
  1038.         $uri      substr$uri);
  1039.     } elseif ( === stripos$uri'https://' ) ) {
  1040.         $protocol 'https://';
  1041.         $uri      substr$uri);
  1042.     } else {
  1043.         $protocol '';
  1044.     }
  1045.     if ( str_contains$uri'?' ) ) {
  1046.         list( $base$query ) = explode'?'$uri);
  1047.         $base                .= '?';
  1048.     } elseif ( $protocol || ! str_contains$uri'=' ) ) {
  1049.         $base  $uri '?';
  1050.         $query '';
  1051.     } else {
  1052.         $base  '';
  1053.         $query $uri;
  1054.     }
  1055.     wp_parse_str$query$qs );
  1056.     $qs urlencode_deep$qs ); // This re-URL-encodes things that were already in the query string.
  1057.     if ( is_array$args[0] ) ) {
  1058.         foreach ( $args[0] as $k => $v ) {
  1059.             $qs$k ] = $v;
  1060.         }
  1061.     } else {
  1062.         $qs$args[0] ] = $args[1];
  1063.     }
  1064.     foreach ( $qs as $k => $v ) {
  1065.         if ( false === $v ) {
  1066.             unset( $qs$k ] );
  1067.         }
  1068.     }
  1069.     $ret build_query$qs );
  1070.     $ret trim$ret'?' );
  1071.     $ret preg_replace'#=(&|$)#''$1'$ret );
  1072.     $ret $protocol $base $ret $frag;
  1073.     $ret rtrim$ret'?' );
  1074.     $ret str_replace'?#''#'$ret );
  1075.     return $ret;
  1076. }
  1077. /**
  1078.  * Removes an item or items from a query string.
  1079.  *
  1080.  * Important: The return value of remove_query_arg() is not escaped by default. Output should be
  1081.  * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
  1082.  * (XSS) attacks.
  1083.  *
  1084.  * @since 1.5.0
  1085.  *
  1086.  * @param string|string[] $key   Query key or keys to remove.
  1087.  * @param false|string    $query Optional. When false uses the current URL. Default false.
  1088.  * @return string New URL query string.
  1089.  */
  1090. function remove_query_arg$key$query false ) {
  1091.     if ( is_array$key ) ) { // Removing multiple keys.
  1092.         foreach ( $key as $k ) {
  1093.             $query add_query_arg$kfalse$query );
  1094.         }
  1095.         return $query;
  1096.     }
  1097.     return add_query_arg$keyfalse$query );
  1098. }
  1099. /**
  1100.  * Returns an array of single-use query variable names that can be removed from a URL.
  1101.  *
  1102.  * @since 4.4.0
  1103.  *
  1104.  * @return string[] An array of query variable names to remove from the URL.
  1105.  */
  1106. function wp_removable_query_args() {
  1107.     $removable_query_args = array(
  1108.         'activate',
  1109.         'activated',
  1110.         'admin_email_remind_later',
  1111.         'approved',
  1112.         'core-major-auto-updates-saved',
  1113.         'deactivate',
  1114.         'delete_count',
  1115.         'deleted',
  1116.         'disabled',
  1117.         'doing_wp_cron',
  1118.         'enabled',
  1119.         'error',
  1120.         'hotkeys_highlight_first',
  1121.         'hotkeys_highlight_last',
  1122.         'ids',
  1123.         'locked',
  1124.         'message',
  1125.         'same',
  1126.         'saved',
  1127.         'settings-updated',
  1128.         'skipped',
  1129.         'spammed',
  1130.         'trashed',
  1131.         'unspammed',
  1132.         'untrashed',
  1133.         'update',
  1134.         'updated',
  1135.         'wp-post-new-reload',
  1136.     );
  1137.     /**
  1138.      * Filters the list of query variable names to remove.
  1139.      *
  1140.      * @since 4.2.0
  1141.      *
  1142.      * @param string[] $removable_query_args An array of query variable names to remove from a URL.
  1143.      */
  1144.     return apply_filters'removable_query_args'$removable_query_args );
  1145. }
  1146. /**
  1147.  * Walks the array while sanitizing the contents.
  1148.  *
  1149.  * @since 0.71
  1150.  * @since 5.5.0 Non-string values are left untouched.
  1151.  *
  1152.  * @param array $input_array Array to walk while sanitizing contents.
  1153.  * @return array Sanitized $input_array.
  1154.  */
  1155. function add_magic_quotes$input_array ) {
  1156.     foreach ( (array) $input_array as $k => $v ) {
  1157.         if ( is_array$v ) ) {
  1158.             $input_array$k ] = add_magic_quotes$v );
  1159.         } elseif ( is_string$v ) ) {
  1160.             $input_array$k ] = addslashes$v );
  1161.         }
  1162.     }
  1163.     return $input_array;
  1164. }
  1165. /**
  1166.  * HTTP request for URI to retrieve content.
  1167.  *
  1168.  * @since 1.5.1
  1169.  *
  1170.  * @see wp_safe_remote_get()
  1171.  *
  1172.  * @param string $uri URI/URL of web page to retrieve.
  1173.  * @return string|false HTTP content. False on failure.
  1174.  */
  1175. function wp_remote_fopen$uri ) {
  1176.     $parsed_url parse_url$uri );
  1177.     if ( ! $parsed_url || ! is_array$parsed_url ) ) {
  1178.         return false;
  1179.     }
  1180.     $options            = array();
  1181.     $options['timeout'] = 10;
  1182.     $response wp_safe_remote_get$uri$options );
  1183.     if ( is_wp_error$response ) ) {
  1184.         return false;
  1185.     }
  1186.     return wp_remote_retrieve_body$response );
  1187. }
  1188. /**
  1189.  * Sets up the WordPress query.
  1190.  *
  1191.  * @since 2.0.0
  1192.  *
  1193.  * @global WP       $wp           Current WordPress environment instance.
  1194.  * @global WP_Query $wp_query     WordPress Query object.
  1195.  * @global WP_Query $wp_the_query Copy of the WordPress Query object.
  1196.  *
  1197.  * @param string|array $query_vars Default WP_Query arguments.
  1198.  */
  1199. function wp$query_vars '' ) {
  1200.     global $wp$wp_query$wp_the_query;
  1201.     $wp->main$query_vars );
  1202.     if ( ! isset( $wp_the_query ) ) {
  1203.         $wp_the_query $wp_query;
  1204.     }
  1205. }
  1206. /**
  1207.  * Retrieves the description for the HTTP status.
  1208.  *
  1209.  * @since 2.3.0
  1210.  * @since 3.9.0 Added status codes 418, 428, 429, 431, and 511.
  1211.  * @since 4.5.0 Added status codes 308, 421, and 451.
  1212.  * @since 5.1.0 Added status code 103.
  1213.  * @since 6.6.0 Added status code 425.
  1214.  *
  1215.  * @global array $wp_header_to_desc
  1216.  *
  1217.  * @param int $code HTTP status code.
  1218.  * @return string Status description if found, an empty string otherwise.
  1219.  */
  1220. function get_status_header_desc$code ) {
  1221.     global $wp_header_to_desc;
  1222.     $code absint$code );
  1223.     if ( ! isset( $wp_header_to_desc ) ) {
  1224.         $wp_header_to_desc = array(
  1225.             100 => 'Continue',
  1226.             101 => 'Switching Protocols',
  1227.             102 => 'Processing',
  1228.             103 => 'Early Hints',
  1229.             200 => 'OK',
  1230.             201 => 'Created',
  1231.             202 => 'Accepted',
  1232.             203 => 'Non-Authoritative Information',
  1233.             204 => 'No Content',
  1234.             205 => 'Reset Content',
  1235.             206 => 'Partial Content',
  1236.             207 => 'Multi-Status',
  1237.             226 => 'IM Used',
  1238.             300 => 'Multiple Choices',
  1239.             301 => 'Moved Permanently',
  1240.             302 => 'Found',
  1241.             303 => 'See Other',
  1242.             304 => 'Not Modified',
  1243.             305 => 'Use Proxy',
  1244.             306 => 'Reserved',
  1245.             307 => 'Temporary Redirect',
  1246.             308 => 'Permanent Redirect',
  1247.             400 => 'Bad Request',
  1248.             401 => 'Unauthorized',
  1249.             402 => 'Payment Required',
  1250.             403 => 'Forbidden',
  1251.             404 => 'Not Found',
  1252.             405 => 'Method Not Allowed',
  1253.             406 => 'Not Acceptable',
  1254.             407 => 'Proxy Authentication Required',
  1255.             408 => 'Request Timeout',
  1256.             409 => 'Conflict',
  1257.             410 => 'Gone',
  1258.             411 => 'Length Required',
  1259.             412 => 'Precondition Failed',
  1260.             413 => 'Request Entity Too Large',
  1261.             414 => 'Request-URI Too Long',
  1262.             415 => 'Unsupported Media Type',
  1263.             416 => 'Requested Range Not Satisfiable',
  1264.             417 => 'Expectation Failed',
  1265.             418 => 'I\'m a teapot',
  1266.             421 => 'Misdirected Request',
  1267.             422 => 'Unprocessable Entity',
  1268.             423 => 'Locked',
  1269.             424 => 'Failed Dependency',
  1270.             425 => 'Too Early',
  1271.             426 => 'Upgrade Required',
  1272.             428 => 'Precondition Required',
  1273.             429 => 'Too Many Requests',
  1274.             431 => 'Request Header Fields Too Large',
  1275.             451 => 'Unavailable For Legal Reasons',
  1276.             500 => 'Internal Server Error',
  1277.             501 => 'Not Implemented',
  1278.             502 => 'Bad Gateway',
  1279.             503 => 'Service Unavailable',
  1280.             504 => 'Gateway Timeout',
  1281.             505 => 'HTTP Version Not Supported',
  1282.             506 => 'Variant Also Negotiates',
  1283.             507 => 'Insufficient Storage',
  1284.             510 => 'Not Extended',
  1285.             511 => 'Network Authentication Required',
  1286.         );
  1287.     }
  1288.     if ( isset( $wp_header_to_desc$code ] ) ) {
  1289.         return $wp_header_to_desc$code ];
  1290.     } else {
  1291.         return '';
  1292.     }
  1293. }
  1294. /**
  1295.  * Sets HTTP status header.
  1296.  *
  1297.  * @since 2.0.0
  1298.  * @since 4.4.0 Added the `$description` parameter.
  1299.  *
  1300.  * @see get_status_header_desc()
  1301.  *
  1302.  * @param int    $code        HTTP status code.
  1303.  * @param string $description Optional. A custom description for the HTTP status.
  1304.  *                            Defaults to the result of get_status_header_desc() for the given code.
  1305.  */
  1306. function status_header$code$description '' ) {
  1307.     if ( ! $description ) {
  1308.         $description get_status_header_desc$code );
  1309.     }
  1310.     if ( empty( $description ) ) {
  1311.         return;
  1312.     }
  1313.     $protocol      wp_get_server_protocol();
  1314.     $status_header "$protocol $code $description";
  1315.     if ( function_exists'apply_filters' ) ) {
  1316.         /**
  1317.          * Filters an HTTP status header.
  1318.          *
  1319.          * @since 2.2.0
  1320.          *
  1321.          * @param string $status_header HTTP status header.
  1322.          * @param int    $code          HTTP status code.
  1323.          * @param string $description   Description for the status code.
  1324.          * @param string $protocol      Server protocol.
  1325.          */
  1326.         $status_header apply_filters'status_header'$status_header$code$description$protocol );
  1327.     }
  1328.     if ( ! headers_sent() ) {
  1329.         header$status_headertrue$code );
  1330.     }
  1331. }
  1332. /**
  1333.  * Gets the HTTP header information to prevent caching.
  1334.  *
  1335.  * The several different headers cover the different ways cache prevention
  1336.  * is handled by different browsers or intermediate caches such as proxy servers.
  1337.  *
  1338.  * @since 2.8.0
  1339.  * @since 6.3.0 The `Cache-Control` header for logged in users now includes the
  1340.  *              `no-store` and `private` directives.
  1341.  * @since 6.8.0 The `Cache-Control` header now includes the `no-store` and `private`
  1342.  *              directives regardless of whether a user is logged in.
  1343.  *
  1344.  * @return array The associative array of header names and field values.
  1345.  */
  1346. function wp_get_nocache_headers() {
  1347.     $cache_control 'no-cache, must-revalidate, max-age=0, no-store, private';
  1348.     $headers = array(
  1349.         'Expires'       => 'Wed, 11 Jan 1984 05:00:00 GMT',
  1350.         'Cache-Control' => $cache_control,
  1351.     );
  1352.     if ( function_exists'apply_filters' ) ) {
  1353.         /**
  1354.          * Filters the cache-controlling HTTP headers that are used to prevent caching.
  1355.          *
  1356.          * @since 2.8.0
  1357.          *
  1358.          * @see wp_get_nocache_headers()
  1359.          *
  1360.          * @param array $headers Header names and field values.
  1361.          */
  1362.         $headers = (array) apply_filters'nocache_headers'$headers );
  1363.     }
  1364.     $headers['Last-Modified'] = false;
  1365.     return $headers;
  1366. }
  1367. /**
  1368.  * Sets the HTTP headers to prevent caching for the different browsers.
  1369.  *
  1370.  * Different browsers support different nocache headers, so several
  1371.  * headers must be sent so that all of them get the point that no
  1372.  * caching should occur.
  1373.  *
  1374.  * @since 2.0.0
  1375.  *
  1376.  * @see wp_get_nocache_headers()
  1377.  */
  1378. function nocache_headers() {
  1379.     if ( headers_sent() ) {
  1380.         return;
  1381.     }
  1382.     $headers wp_get_nocache_headers();
  1383.     unset( $headers['Last-Modified'] );
  1384.     header_remove'Last-Modified' );
  1385.     foreach ( $headers as $name => $field_value ) {
  1386.         header"{$name}{$field_value});
  1387.     }
  1388. }
  1389. /**
  1390.  * Sets the HTTP headers for caching for 10 days with JavaScript content type.
  1391.  *
  1392.  * @since 2.1.0
  1393.  */
  1394. function cache_javascript_headers() {
  1395.     $expires_offset 10 DAY_IN_SECONDS;
  1396.     header'Content-Type: text/javascript; charset=' get_bloginfo'charset' ) );
  1397.     header'Vary: Accept-Encoding' ); // Handle proxies.
  1398.     header'Expires: ' gmdate'D, d M Y H:i:s'time() + $expires_offset ) . ' GMT' );
  1399. }
  1400. /**
  1401.  * Retrieves the number of database queries during the WordPress execution.
  1402.  *
  1403.  * @since 2.0.0
  1404.  *
  1405.  * @global wpdb $wpdb WordPress database abstraction object.
  1406.  *
  1407.  * @return int Number of database queries.
  1408.  */
  1409. function get_num_queries() {
  1410.     global $wpdb;
  1411.     return $wpdb->num_queries;
  1412. }
  1413. /**
  1414.  * Determines whether input is yes or no.
  1415.  *
  1416.  * Must be 'y' to be true.
  1417.  *
  1418.  * @since 1.0.0
  1419.  *
  1420.  * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
  1421.  * @return bool True if 'y', false on anything else.
  1422.  */
  1423. function bool_from_yn$yn ) {
  1424.     return ( 'y' === strtolower$yn ) );
  1425. }
  1426. /**
  1427.  * Loads the feed template from the use of an action hook.
  1428.  *
  1429.  * If the feed action does not have a hook, then the function will die with a
  1430.  * message telling the visitor that the feed is not valid.
  1431.  *
  1432.  * It is better to only have one hook for each feed.
  1433.  *
  1434.  * @since 2.1.0
  1435.  *
  1436.  * @global WP_Query $wp_query WordPress Query object.
  1437.  */
  1438. function do_feed() {
  1439.     global $wp_query;
  1440.     $feed get_query_var'feed' );
  1441.     // Remove the pad, if present.
  1442.     $feed preg_replace'/^_+/'''$feed );
  1443.     if ( '' === $feed || 'feed' === $feed ) {
  1444.         $feed get_default_feed();
  1445.     }
  1446.     if ( ! has_action"do_feed_{$feed}) ) {
  1447.         wp_die__'<strong>Error:</strong> This is not a valid feed template.' ), '', array( 'response' => 404 ) );
  1448.     }
  1449.     /**
  1450.      * Fires once the given feed is loaded.
  1451.      *
  1452.      * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
  1453.      *
  1454.      * Possible hook names include:
  1455.      *
  1456.      *  - `do_feed_atom`
  1457.      *  - `do_feed_rdf`
  1458.      *  - `do_feed_rss`
  1459.      *  - `do_feed_rss2`
  1460.      *
  1461.      * @since 2.1.0
  1462.      * @since 4.4.0 The `$feed` parameter was added.
  1463.      *
  1464.      * @param bool   $is_comment_feed Whether the feed is a comment feed.
  1465.      * @param string $feed            The feed name.
  1466.      */
  1467.     do_action"do_feed_{$feed}"$wp_query->is_comment_feed$feed );
  1468. }
  1469. /**
  1470.  * Loads the RDF RSS 0.91 Feed template.
  1471.  *
  1472.  * @since 2.1.0
  1473.  *
  1474.  * @see load_template()
  1475.  */
  1476. function do_feed_rdf() {
  1477.     load_templateABSPATH WPINC '/feed-rdf.php' );
  1478. }
  1479. /**
  1480.  * Loads the RSS 1.0 Feed Template.
  1481.  *
  1482.  * @since 2.1.0
  1483.  *
  1484.  * @see load_template()
  1485.  */
  1486. function do_feed_rss() {
  1487.     load_templateABSPATH WPINC '/feed-rss.php' );
  1488. }
  1489. /**
  1490.  * Loads either the RSS2 comment feed or the RSS2 posts feed.
  1491.  *
  1492.  * @since 2.1.0
  1493.  *
  1494.  * @see load_template()
  1495.  *
  1496.  * @param bool $for_comments True for the comment feed, false for normal feed.
  1497.  */
  1498. function do_feed_rss2$for_comments ) {
  1499.     if ( $for_comments ) {
  1500.         load_templateABSPATH WPINC '/feed-rss2-comments.php' );
  1501.     } else {
  1502.         load_templateABSPATH WPINC '/feed-rss2.php' );
  1503.     }
  1504. }
  1505. /**
  1506.  * Loads either Atom comment feed or Atom posts feed.
  1507.  *
  1508.  * @since 2.1.0
  1509.  *
  1510.  * @see load_template()
  1511.  *
  1512.  * @param bool $for_comments True for the comment feed, false for normal feed.
  1513.  */
  1514. function do_feed_atom$for_comments ) {
  1515.     if ( $for_comments ) {
  1516.         load_templateABSPATH WPINC '/feed-atom-comments.php' );
  1517.     } else {
  1518.         load_templateABSPATH WPINC '/feed-atom.php' );
  1519.     }
  1520. }
  1521. /**
  1522.  * Displays the default robots.txt file content.
  1523.  *
  1524.  * @since 2.1.0
  1525.  * @since 5.3.0 Remove the "Disallow: /" output if search engine visibility is
  1526.  *              discouraged in favor of robots meta HTML tag via wp_robots_no_robots()
  1527.  *              filter callback.
  1528.  */
  1529. function do_robots() {
  1530.     header'Content-Type: text/plain; charset=utf-8' );
  1531.     /**
  1532.      * Fires when displaying the robots.txt file.
  1533.      *
  1534.      * @since 2.1.0
  1535.      */
  1536.     do_action'do_robotstxt' );
  1537.     $output "User-agent: *\n";
  1538.     $public = (bool) get_option'blog_public' );
  1539.     $site_url parse_urlsite_url() );
  1540.     $path     = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
  1541.     $output  .= "Disallow: $path/wp-admin/\n";
  1542.     $output  .= "Allow: $path/wp-admin/admin-ajax.php\n";
  1543.     /**
  1544.      * Filters the robots.txt output.
  1545.      *
  1546.      * @since 3.0.0
  1547.      *
  1548.      * @param string $output The robots.txt output.
  1549.      * @param bool   $public Whether the site is considered "public".
  1550.      */
  1551.     echo apply_filters'robots_txt'$output$public );
  1552. }
  1553. /**
  1554.  * Displays the favicon.ico file content.
  1555.  *
  1556.  * @since 5.4.0
  1557.  */
  1558. function do_favicon() {
  1559.     /**
  1560.      * Fires when serving the favicon.ico file.
  1561.      *
  1562.      * @since 5.4.0
  1563.      */
  1564.     do_action'do_faviconico' );
  1565.     wp_redirectget_site_icon_url32includes_url'images/w-logo-blue-white-bg.png' ) ) );
  1566.     exit;
  1567. }
  1568. /**
  1569.  * Determines whether WordPress is already installed.
  1570.  *
  1571.  * The cache will be checked first. If you have a cache plugin, which saves
  1572.  * the cache values, then this will work. If you use the default WordPress
  1573.  * cache, and the database goes away, then you might have problems.
  1574.  *
  1575.  * Checks for the 'siteurl' option for whether WordPress is installed.
  1576.  *
  1577.  * For more information on this and similar theme functions, check out
  1578.  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  1579.  * Conditional Tags} article in the Theme Developer Handbook.
  1580.  *
  1581.  * @since 2.1.0
  1582.  *
  1583.  * @global wpdb $wpdb WordPress database abstraction object.
  1584.  *
  1585.  * @return bool Whether the site is already installed.
  1586.  */
  1587. function is_blog_installed() {
  1588.     global $wpdb;
  1589.     /*
  1590.      * Check cache first. If options table goes away and we have true
  1591.      * cached, oh well.
  1592.      */
  1593.     if ( wp_cache_get'is_blog_installed' ) ) {
  1594.         return true;
  1595.     }
  1596.     $suppress $wpdb->suppress_errors();
  1597.     if ( ! wp_installing() ) {
  1598.         $alloptions wp_load_alloptions();
  1599.     }
  1600.     // If siteurl is not set to autoload, check it specifically.
  1601.     if ( ! isset( $alloptions['siteurl'] ) ) {
  1602.         $installed $wpdb->get_var"SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
  1603.     } else {
  1604.         $installed $alloptions['siteurl'];
  1605.     }
  1606.     $wpdb->suppress_errors$suppress );
  1607.     $installed = ! empty( $installed );
  1608.     wp_cache_set'is_blog_installed'$installed );
  1609.     if ( $installed ) {
  1610.         return true;
  1611.     }
  1612.     // If visiting repair.php, return true and let it take over.
  1613.     if ( defined'WP_REPAIRING' ) ) {
  1614.         return true;
  1615.     }
  1616.     $suppress $wpdb->suppress_errors();
  1617.     /*
  1618.      * Loop over the WP tables. If none exist, then scratch installation is allowed.
  1619.      * If one or more exist, suggest table repair since we got here because the
  1620.      * options table could not be accessed.
  1621.      */
  1622.     $wp_tables $wpdb->tables();
  1623.     foreach ( $wp_tables as $table ) {
  1624.         // The existence of custom user tables shouldn't suggest an unwise state or prevent a clean installation.
  1625.         if ( defined'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE === $table ) {
  1626.             continue;
  1627.         }
  1628.         if ( defined'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE === $table ) {
  1629.             continue;
  1630.         }
  1631.         $described_table $wpdb->get_results"DESCRIBE $table;" );
  1632.         if (
  1633.             ( ! $described_table && empty( $wpdb->last_error ) ) ||
  1634.             ( is_array$described_table ) && === count$described_table ) )
  1635.         ) {
  1636.             continue;
  1637.         }
  1638.         // One or more tables exist. This is not good.
  1639.         wp_load_translations_early();
  1640.         // Die with a DB error.
  1641.         $wpdb->error sprintf(
  1642.             /* translators: %s: Database repair URL. */
  1643.             __'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ),
  1644.             'maint/repair.php?referrer=is_blog_installed'
  1645.         );
  1646.         dead_db();
  1647.     }
  1648.     $wpdb->suppress_errors$suppress );
  1649.     wp_cache_set'is_blog_installed'false );
  1650.     return false;
  1651. }
  1652. /**
  1653.  * Retrieves URL with nonce added to URL query.
  1654.  *
  1655.  * @since 2.0.4
  1656.  *
  1657.  * @param string     $actionurl URL to add nonce action.
  1658.  * @param int|string $action    Optional. Nonce action name. Default -1.
  1659.  * @param string     $name      Optional. Nonce name. Default '_wpnonce'.
  1660.  * @return string Escaped URL with nonce action added.
  1661.  */
  1662. function wp_nonce_url$actionurl$action = -1$name '_wpnonce' ) {
  1663.     $actionurl str_replace'&amp;''&'$actionurl );
  1664.     return esc_htmladd_query_arg$namewp_create_nonce$action ), $actionurl ) );
  1665. }
  1666. /**
  1667.  * Retrieves or display nonce hidden field for forms.
  1668.  *
  1669.  * The nonce field is used to validate that the contents of the form came from
  1670.  * the location on the current site and not somewhere else. The nonce does not
  1671.  * offer absolute protection, but should protect against most cases. It is very
  1672.  * important to use nonce field in forms.
  1673.  *
  1674.  * The $action and $name are optional, but if you want to have better security,
  1675.  * it is strongly suggested to set those two parameters. It is easier to just
  1676.  * call the function without any parameters, because validation of the nonce
  1677.  * doesn't require any parameters, but since crackers know what the default is
  1678.  * it won't be difficult for them to find a way around your nonce and cause
  1679.  * damage.
  1680.  *
  1681.  * The input name will be whatever $name value you gave. The input value will be
  1682.  * the nonce creation value.
  1683.  *
  1684.  * @since 2.0.4
  1685.  *
  1686.  * @param int|string $action  Optional. Action name. Default -1.
  1687.  * @param string     $name    Optional. Nonce name. Default '_wpnonce'.
  1688.  * @param bool       $referer Optional. Whether to set the referer field for validation. Default true.
  1689.  * @param bool       $display Optional. Whether to display or return hidden form field. Default true.
  1690.  * @return string Nonce field HTML markup.
  1691.  */
  1692. function wp_nonce_field$action = -1$name '_wpnonce'$referer true$display true ) {
  1693.     $name        esc_attr$name );
  1694.     $nonce_field '<input type="hidden" id="' $name '" name="' $name '" value="' wp_create_nonce$action ) . '" />';
  1695.     if ( $referer ) {
  1696.         $nonce_field .= wp_referer_fieldfalse );
  1697.     }
  1698.     if ( $display ) {
  1699.         echo $nonce_field;
  1700.     }
  1701.     return $nonce_field;
  1702. }
  1703. /**
  1704.  * Retrieves or displays referer hidden field for forms.
  1705.  *
  1706.  * The referer link is the current Request URI from the server super global. The
  1707.  * input name is '_wp_http_referer', in case you wanted to check manually.
  1708.  *
  1709.  * @since 2.0.4
  1710.  *
  1711.  * @param bool $display Optional. Whether to echo or return the referer field. Default true.
  1712.  * @return string Referer field HTML markup.
  1713.  */
  1714. function wp_referer_field$display true ) {
  1715.     $request_url   remove_query_arg'_wp_http_referer' );
  1716.     $referer_field '<input type="hidden" name="_wp_http_referer" value="' esc_url$request_url ) . '" />';
  1717.     if ( $display ) {
  1718.         echo $referer_field;
  1719.     }
  1720.     return $referer_field;
  1721. }
  1722. /**
  1723.  * Retrieves or displays original referer hidden field for forms.
  1724.  *
  1725.  * The input name is '_wp_original_http_referer' and will be either the same
  1726.  * value of wp_referer_field(), if that was posted already or it will be the
  1727.  * current page, if it doesn't exist.
  1728.  *
  1729.  * @since 2.0.4
  1730.  *
  1731.  * @param bool   $display      Optional. Whether to echo the original http referer. Default true.
  1732.  * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
  1733.  *                             Default 'current'.
  1734.  * @return string Original referer field.
  1735.  */
  1736. function wp_original_referer_field$display true$jump_back_to 'current' ) {
  1737.     $ref wp_get_original_referer();
  1738.     if ( ! $ref ) {
  1739.         $ref = ( 'previous' === $jump_back_to ) ? wp_get_referer() : wp_unslash$_SERVER['REQUEST_URI'] );
  1740.     }
  1741.     $orig_referer_field '<input type="hidden" name="_wp_original_http_referer" value="' esc_attr$ref ) . '" />';
  1742.     if ( $display ) {
  1743.         echo $orig_referer_field;
  1744.     }
  1745.     return $orig_referer_field;
  1746. }
  1747. /**
  1748.  * Retrieves referer from '_wp_http_referer' or HTTP referer.
  1749.  *
  1750.  * If it's the same as the current request URL, will return false.
  1751.  *
  1752.  * @since 2.0.4
  1753.  *
  1754.  * @return string|false Referer URL on success, false on failure.
  1755.  */
  1756. function wp_get_referer() {
  1757.     // Return early if called before wp_validate_redirect() is defined.
  1758.     if ( ! function_exists'wp_validate_redirect' ) ) {
  1759.         return false;
  1760.     }
  1761.     $ref wp_get_raw_referer();
  1762.     if ( $ref && wp_unslash$_SERVER['REQUEST_URI'] ) !== $ref
  1763.         && home_url() . wp_unslash$_SERVER['REQUEST_URI'] ) !== $ref
  1764.     ) {
  1765.         return wp_validate_redirect$reffalse );
  1766.     }
  1767.     return false;
  1768. }
  1769. /**
  1770.  * Retrieves unvalidated referer from the '_wp_http_referer' URL query variable or the HTTP referer.
  1771.  *
  1772.  * If the value of the '_wp_http_referer' URL query variable is not a string then it will be ignored.
  1773.  *
  1774.  * Do not use for redirects, use wp_get_referer() instead.
  1775.  *
  1776.  * @since 4.5.0
  1777.  *
  1778.  * @return string|false Referer URL on success, false on failure.
  1779.  */
  1780. function wp_get_raw_referer() {
  1781.     if ( ! empty( $_REQUEST['_wp_http_referer'] ) && is_string$_REQUEST['_wp_http_referer'] ) ) {
  1782.         return wp_unslash$_REQUEST['_wp_http_referer'] );
  1783.     } elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
  1784.         return wp_unslash$_SERVER['HTTP_REFERER'] );
  1785.     }
  1786.     return false;
  1787. }
  1788. /**
  1789.  * Retrieves original referer that was posted, if it exists.
  1790.  *
  1791.  * @since 2.0.4
  1792.  *
  1793.  * @return string|false Original referer URL on success, false on failure.
  1794.  */
  1795. function wp_get_original_referer() {
  1796.     // Return early if called before wp_validate_redirect() is defined.
  1797.     if ( ! function_exists'wp_validate_redirect' ) ) {
  1798.         return false;
  1799.     }
  1800.     if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) ) {
  1801.         return wp_validate_redirectwp_unslash$_REQUEST['_wp_original_http_referer'] ), false );
  1802.     }
  1803.     return false;
  1804. }
  1805. /**
  1806.  * Recursive directory creation based on full path.
  1807.  *
  1808.  * Will attempt to set permissions on folders.
  1809.  *
  1810.  * @since 2.0.1
  1811.  *
  1812.  * @param string $target Full path to attempt to create.
  1813.  * @return bool Whether the path was created. True if path already exists.
  1814.  */
  1815. function wp_mkdir_p$target ) {
  1816.     $wrapper null;
  1817.     // Strip the protocol.
  1818.     if ( wp_is_stream$target ) ) {
  1819.         list( $wrapper$target ) = explode'://'$target);
  1820.     }
  1821.     // From php.net/mkdir user contributed notes.
  1822.     $target str_replace'//''/'$target );
  1823.     // Put the wrapper back on the target.
  1824.     if ( null !== $wrapper ) {
  1825.         $target $wrapper '://' $target;
  1826.     }
  1827.     /*
  1828.      * Safe mode fails with a trailing slash under certain PHP versions.
  1829.      * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
  1830.      */
  1831.     $target rtrim$target'/' );
  1832.     if ( empty( $target ) ) {
  1833.         $target '/';
  1834.     }
  1835.     if ( file_exists$target ) ) {
  1836.         return @is_dir$target );
  1837.     }
  1838.     // Do not allow path traversals.
  1839.     if ( str_contains$target'../' ) || str_contains$target'..' DIRECTORY_SEPARATOR ) ) {
  1840.         return false;
  1841.     }
  1842.     // We need to find the permissions of the parent folder that exists and inherit that.
  1843.     $target_parent dirname$target );
  1844.     while ( '.' !== $target_parent && ! is_dir$target_parent ) && dirname$target_parent ) !== $target_parent ) {
  1845.         $target_parent dirname$target_parent );
  1846.     }
  1847.     // Get the permission bits.
  1848.     $stat = @stat$target_parent );
  1849.     if ( $stat ) {
  1850.         $dir_perms $stat['mode'] & 0007777;
  1851.     } else {
  1852.         $dir_perms 0777;
  1853.     }
  1854.     if ( @mkdir$target$dir_permstrue ) ) {
  1855.         /*
  1856.          * If a umask is set that modifies $dir_perms, we'll have to re-set
  1857.          * the $dir_perms correctly with chmod()
  1858.          */
  1859.         if ( ( $dir_perms & ~umask() ) !== $dir_perms ) {
  1860.             $folder_parts explode'/'substr$targetstrlen$target_parent ) + ) );
  1861.             for ( $i 1$c count$folder_parts ); $i <= $c$i++ ) {
  1862.                 chmod$target_parent '/' implode'/'array_slice$folder_parts0$i ) ), $dir_perms );
  1863.             }
  1864.         }
  1865.         return true;
  1866.     }
  1867.     return false;
  1868. }
  1869. /**
  1870.  * Tests if a given filesystem path is absolute.
  1871.  *
  1872.  * For example, '/foo/bar', or 'c:\windows'.
  1873.  *
  1874.  * @since 2.5.0
  1875.  *
  1876.  * @param string $path File path.
  1877.  * @return bool True if path is absolute, false is not absolute.
  1878.  */
  1879. function path_is_absolute$path ) {
  1880.     /*
  1881.      * Check to see if the path is a stream and check to see if its an actual
  1882.      * path or file as realpath() does not support stream wrappers.
  1883.      */
  1884.     if ( wp_is_stream$path ) && ( is_dir$path ) || is_file$path ) ) ) {
  1885.         return true;
  1886.     }
  1887.     /*
  1888.      * This is definitive if true but fails if $path does not exist or contains
  1889.      * a symbolic link.
  1890.      */
  1891.     if ( realpath$path ) === $path ) {
  1892.         return true;
  1893.     }
  1894.     if ( strlen$path ) === || '.' === $path[0] ) {
  1895.         return false;
  1896.     }
  1897.     // Windows allows absolute paths like this.
  1898.     if ( preg_match'#^[a-zA-Z]:\\\\#'$path ) ) {
  1899.         return true;
  1900.     }
  1901.     // A path starting with / or \ is absolute; anything else is relative.
  1902.     return ( '/' === $path[0] || '\\' === $path[0] );
  1903. }
  1904. /**
  1905.  * Joins two filesystem paths together.
  1906.  *
  1907.  * For example, 'give me $path relative to $base'. If the $path is absolute,
  1908.  * then it the full path is returned.
  1909.  *
  1910.  * @since 2.5.0
  1911.  *
  1912.  * @param string $base Base path.
  1913.  * @param string $path Path relative to $base.
  1914.  * @return string The path with the base or absolute path.
  1915.  */
  1916. function path_join$base$path ) {
  1917.     if ( path_is_absolute$path ) ) {
  1918.         return $path;
  1919.     }
  1920.     return rtrim$base'/' ) . '/' $path;
  1921. }
  1922. /**
  1923.  * Normalizes a filesystem path.
  1924.  *
  1925.  * On windows systems, replaces backslashes with forward slashes
  1926.  * and forces upper-case drive letters.
  1927.  * Allows for two leading slashes for Windows network shares, but
  1928.  * ensures that all other duplicate slashes are reduced to a single.
  1929.  *
  1930.  * @since 3.9.0
  1931.  * @since 4.4.0 Ensures upper-case drive letters on Windows systems.
  1932.  * @since 4.5.0 Allows for Windows network shares.
  1933.  * @since 4.9.7 Allows for PHP file wrappers.
  1934.  *
  1935.  * @param string $path Path to normalize.
  1936.  * @return string Normalized path.
  1937.  */
  1938. function wp_normalize_path$path ) {
  1939.     $wrapper '';
  1940.     if ( wp_is_stream$path ) ) {
  1941.         list( $wrapper$path ) = explode'://'$path);
  1942.         $wrapper .= '://';
  1943.     }
  1944.     // Standardize all paths to use '/'.
  1945.     $path str_replace'\\''/'$path );
  1946.     // Replace multiple slashes down to a singular, allowing for network shares having two slashes.
  1947.     $path preg_replace'|(?<=.)/+|''/'$path );
  1948.     // Windows paths should uppercase the drive letter.
  1949.     if ( ':' === substr$path1) ) {
  1950.         $path ucfirst$path );
  1951.     }
  1952.     return $wrapper $path;
  1953. }
  1954. /**
  1955.  * Determines a writable directory for temporary files.
  1956.  *
  1957.  * Function's preference is the return value of sys_get_temp_dir(),
  1958.  * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
  1959.  * before finally defaulting to /tmp/
  1960.  *
  1961.  * In the event that this function does not find a writable location,
  1962.  * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
  1963.  *
  1964.  * @since 2.5.0
  1965.  *
  1966.  * @return string Writable temporary directory.
  1967.  */
  1968. function get_temp_dir() {
  1969.     static $temp '';
  1970.     if ( defined'WP_TEMP_DIR' ) ) {
  1971.         return trailingslashitWP_TEMP_DIR );
  1972.     }
  1973.     if ( $temp ) {
  1974.         return trailingslashit$temp );
  1975.     }
  1976.     if ( function_exists'sys_get_temp_dir' ) ) {
  1977.         $temp sys_get_temp_dir();
  1978.         if ( @is_dir$temp ) && wp_is_writable$temp ) ) {
  1979.             return trailingslashit$temp );
  1980.         }
  1981.     }
  1982.     $temp ini_get'upload_tmp_dir' );
  1983.     if ( @is_dir$temp ) && wp_is_writable$temp ) ) {
  1984.         return trailingslashit$temp );
  1985.     }
  1986.     $temp WP_CONTENT_DIR '/';
  1987.     if ( is_dir$temp ) && wp_is_writable$temp ) ) {
  1988.         return $temp;
  1989.     }
  1990.     return '/tmp/';
  1991. }
  1992. /**
  1993.  * Determines if a directory is writable.
  1994.  *
  1995.  * This function is used to work around certain ACL issues in PHP primarily
  1996.  * affecting Windows Servers.
  1997.  *
  1998.  * @since 3.6.0
  1999.  *
  2000.  * @see win_is_writable()
  2001.  *
  2002.  * @param string $path Path to check for write-ability.
  2003.  * @return bool Whether the path is writable.
  2004.  */
  2005. function wp_is_writable$path ) {
  2006.     if ( 'Windows' === PHP_OS_FAMILY ) {
  2007.         return win_is_writable$path );
  2008.     }
  2009.     return @is_writable$path );
  2010. }
  2011. /**
  2012.  * Workaround for Windows bug in is_writable() function
  2013.  *
  2014.  * PHP has issues with Windows ACL's for determine if a
  2015.  * directory is writable or not, this works around them by
  2016.  * checking the ability to open files rather than relying
  2017.  * upon PHP to interpret the OS ACL.
  2018.  *
  2019.  * @since 2.8.0
  2020.  *
  2021.  * @see https://bugs.php.net/bug.php?id=27609
  2022.  * @see https://bugs.php.net/bug.php?id=30931
  2023.  *
  2024.  * @param string $path Windows path to check for write-ability.
  2025.  * @return bool Whether the path is writable.
  2026.  */
  2027. function win_is_writable$path ) {
  2028.     if ( '/' === $pathstrlen$path ) - ] ) {
  2029.         // If it looks like a directory, check a random file within the directory.
  2030.         return win_is_writable$path uniqidmt_rand() ) . '.tmp' );
  2031.     } elseif ( is_dir$path ) ) {
  2032.         // If it's a directory (and not a file), check a random file within the directory.
  2033.         return win_is_writable$path '/' uniqidmt_rand() ) . '.tmp' );
  2034.     }
  2035.     // Check tmp file for read/write capabilities.
  2036.     $should_delete_tmp_file = ! file_exists$path );
  2037.     $f = @fopen$path'a' );
  2038.     if ( false === $f ) {
  2039.         return false;
  2040.     }
  2041.     fclose$f );
  2042.     if ( $should_delete_tmp_file ) {
  2043.         unlink$path );
  2044.     }
  2045.     return true;
  2046. }
  2047. /**
  2048.  * Retrieves uploads directory information.
  2049.  *
  2050.  * Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
  2051.  * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
  2052.  * when not uploading files.
  2053.  *
  2054.  * @since 4.5.0
  2055.  *
  2056.  * @see wp_upload_dir()
  2057.  *
  2058.  * @return array See wp_upload_dir() for description.
  2059.  */
  2060. function wp_get_upload_dir() {
  2061.     return wp_upload_dirnullfalse );
  2062. }
  2063. /**
  2064.  * Returns an array containing the current upload directory's path and URL.
  2065.  *
  2066.  * Checks the 'upload_path' option, which should be from the web root folder,
  2067.  * and if it isn't empty it will be used. If it is empty, then the path will be
  2068.  * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
  2069.  * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
  2070.  *
  2071.  * The upload URL path is set either by the 'upload_url_path' option or by using
  2072.  * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
  2073.  *
  2074.  * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
  2075.  * the administration settings panel), then the time will be used. The format
  2076.  * will be year first and then month.
  2077.  *
  2078.  * If the path couldn't be created, then an error will be returned with the key
  2079.  * 'error' containing the error message. The error suggests that the parent
  2080.  * directory is not writable by the server.
  2081.  *
  2082.  * @since 2.0.0
  2083.  * @uses _wp_upload_dir()
  2084.  *
  2085.  * @param string|null $time          Optional. Time formatted in 'yyyy/mm'. Default null.
  2086.  * @param bool        $create_dir    Optional. Whether to check and create the uploads directory.
  2087.  *                                   Default true for backward compatibility.
  2088.  * @param bool        $refresh_cache Optional. Whether to refresh the cache. Default false.
  2089.  * @return array {
  2090.  *     Array of information about the upload directory.
  2091.  *
  2092.  *     @type string       $path    Base directory and subdirectory or full path to upload directory.
  2093.  *     @type string       $url     Base URL and subdirectory or absolute URL to upload directory.
  2094.  *     @type string       $subdir  Subdirectory if uploads use year/month folders option is on.
  2095.  *     @type string       $basedir Path without subdir.
  2096.  *     @type string       $baseurl URL path without subdir.
  2097.  *     @type string|false $error   False or error message.
  2098.  * }
  2099.  */
  2100. function wp_upload_dir$time null$create_dir true$refresh_cache false ) {
  2101.     static $cache = array(), $tested_paths = array();
  2102.     $key sprintf'%d-%s'get_current_blog_id(), (string) $time );
  2103.     if ( $refresh_cache || empty( $cache$key ] ) ) {
  2104.         $cache$key ] = _wp_upload_dir$time );
  2105.     }
  2106.     /**
  2107.      * Filters the uploads directory data.
  2108.      *
  2109.      * @since 2.0.0
  2110.      *
  2111.      * @param array $uploads {
  2112.      *     Array of information about the upload directory.
  2113.      *
  2114.      *     @type string       $path    Base directory and subdirectory or full path to upload directory.
  2115.      *     @type string       $url     Base URL and subdirectory or absolute URL to upload directory.
  2116.      *     @type string       $subdir  Subdirectory if uploads use year/month folders option is on.
  2117.      *     @type string       $basedir Path without subdir.
  2118.      *     @type string       $baseurl URL path without subdir.
  2119.      *     @type string|false $error   False or error message.
  2120.      * }
  2121.      */
  2122.     $uploads apply_filters'upload_dir'$cache$key ] );
  2123.     if ( $create_dir ) {
  2124.         $path $uploads['path'];
  2125.         if ( array_key_exists$path$tested_paths ) ) {
  2126.             $uploads['error'] = $tested_paths$path ];
  2127.         } else {
  2128.             if ( ! wp_mkdir_p$path ) ) {
  2129.                 if ( str_starts_with$uploads['basedir'], ABSPATH ) ) {
  2130.                     $error_path str_replaceABSPATH''$uploads['basedir'] ) . $uploads['subdir'];
  2131.                 } else {
  2132.                     $error_path wp_basename$uploads['basedir'] ) . $uploads['subdir'];
  2133.                 }
  2134.                 $uploads['error'] = sprintf(
  2135.                     /* translators: %s: Directory path. */
  2136.                     __'Unable to create directory %s. Is its parent directory writable by the server?' ),
  2137.                     esc_html$error_path )
  2138.                 );
  2139.             }
  2140.             $tested_paths$path ] = $uploads['error'];
  2141.         }
  2142.     }
  2143.     return $uploads;
  2144. }
  2145. /**
  2146.  * A non-filtered, non-cached version of wp_upload_dir() that doesn't check the path.
  2147.  *
  2148.  * @since 4.5.0
  2149.  * @access private
  2150.  *
  2151.  * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null.
  2152.  * @return array See wp_upload_dir()
  2153.  */
  2154. function _wp_upload_dir$time null ) {
  2155.     $siteurl     get_option'siteurl' );
  2156.     $upload_path trimget_option'upload_path' ) );
  2157.     if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) {
  2158.         $dir WP_CONTENT_DIR '/uploads';
  2159.     } elseif ( ! str_starts_with$upload_pathABSPATH ) ) {
  2160.         // $dir is absolute, $upload_path is (maybe) relative to ABSPATH.
  2161.         $dir path_joinABSPATH$upload_path );
  2162.     } else {
  2163.         $dir $upload_path;
  2164.     }
  2165.     $url get_option'upload_url_path' );
  2166.     if ( ! $url ) {
  2167.         if ( empty( $upload_path ) || ( 'wp-content/uploads' === $upload_path ) || ( $upload_path === $dir ) ) {
  2168.             $url WP_CONTENT_URL '/uploads';
  2169.         } else {
  2170.             $url trailingslashit$siteurl ) . $upload_path;
  2171.         }
  2172.     }
  2173.     /*
  2174.      * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
  2175.      * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
  2176.      */
  2177.     if ( defined'UPLOADS' ) && ! ( is_multisite() && get_site_option'ms_files_rewriting' ) ) ) {
  2178.         $dir ABSPATH UPLOADS;
  2179.         $url trailingslashit$siteurl ) . UPLOADS;
  2180.     }
  2181.     // If multisite (and if not the main site in a post-MU network).
  2182.     if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined'MULTISITE' ) ) ) {
  2183.         if ( ! get_site_option'ms_files_rewriting' ) ) {
  2184.             /*
  2185.              * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
  2186.              * straightforward: Append sites/%d if we're not on the main site (for post-MU
  2187.              * networks). (The extra directory prevents a four-digit ID from conflicting with
  2188.              * a year-based directory for the main site. But if a MU-era network has disabled
  2189.              * ms-files rewriting manually, they don't need the extra directory, as they never
  2190.              * had wp-content/uploads for the main site.)
  2191.              */
  2192.             if ( defined'MULTISITE' ) ) {
  2193.                 $ms_dir '/sites/' get_current_blog_id();
  2194.             } else {
  2195.                 $ms_dir '/' get_current_blog_id();
  2196.             }
  2197.             $dir .= $ms_dir;
  2198.             $url .= $ms_dir;
  2199.         } elseif ( defined'UPLOADS' ) && ! ms_is_switched() ) {
  2200.             /*
  2201.              * Handle the old-form ms-files.php rewriting if the network still has that enabled.
  2202.              * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
  2203.              * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
  2204.              *    there, and
  2205.              * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
  2206.              *    the original blog ID.
  2207.              *
  2208.              * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
  2209.              * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
  2210.              * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
  2211.              * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
  2212.              */
  2213.             if ( defined'BLOGUPLOADDIR' ) ) {
  2214.                 $dir untrailingslashitBLOGUPLOADDIR );
  2215.             } else {
  2216.                 $dir ABSPATH UPLOADS;
  2217.             }
  2218.             $url trailingslashit$siteurl ) . 'files';
  2219.         }
  2220.     }
  2221.     $basedir $dir;
  2222.     $baseurl $url;
  2223.     $subdir '';
  2224.     if ( get_option'uploads_use_yearmonth_folders' ) ) {
  2225.         // Generate the yearly and monthly directories.
  2226.         if ( ! $time ) {
  2227.             $time current_time'mysql' );
  2228.         }
  2229.         $y      substr$time0);
  2230.         $m      substr$time5);
  2231.         $subdir "/$y/$m";
  2232.     }
  2233.     $dir .= $subdir;
  2234.     $url .= $subdir;
  2235.     return array(
  2236.         'path'    => $dir,
  2237.         'url'     => $url,
  2238.         'subdir'  => $subdir,
  2239.         'basedir' => $basedir,
  2240.         'baseurl' => $baseurl,
  2241.         'error'   => false,
  2242.     );
  2243. }
  2244. /**
  2245.  * Gets a filename that is sanitized and unique for the given directory.
  2246.  *
  2247.  * If the filename is not unique, then a number will be added to the filename
  2248.  * before the extension, and will continue adding numbers until the filename
  2249.  * is unique.
  2250.  *
  2251.  * The callback function allows the caller to use their own method to create
  2252.  * unique file names. If defined, the callback should take three arguments:
  2253.  * - directory, base filename, and extension - and return a unique filename.
  2254.  *
  2255.  * @since 2.5.0
  2256.  *
  2257.  * @param string   $dir                      Directory.
  2258.  * @param string   $filename                 File name.
  2259.  * @param callable $unique_filename_callback Callback. Default null.
  2260.  * @return string New filename, if given wasn't unique.
  2261.  */
  2262. function wp_unique_filename$dir$filename$unique_filename_callback null ) {
  2263.     // Sanitize the file name before we begin processing.
  2264.     $filename sanitize_file_name$filename );
  2265.     $ext2     null;
  2266.     // Initialize vars used in the wp_unique_filename filter.
  2267.     $number        '';
  2268.     $alt_filenames = array();
  2269.     // Separate the filename into a name and extension.
  2270.     $ext  pathinfo$filenamePATHINFO_EXTENSION );
  2271.     $name pathinfo$filenamePATHINFO_BASENAME );
  2272.     if ( $ext ) {
  2273.         $ext '.' $ext;
  2274.     }
  2275.     // Edge case: if file is named '.ext', treat as an empty name.
  2276.     if ( $name === $ext ) {
  2277.         $name '';
  2278.     }
  2279.     /*
  2280.      * Increment the file number until we have a unique file to save in $dir.
  2281.      * Use callback if supplied.
  2282.      */
  2283.     if ( $unique_filename_callback && is_callable$unique_filename_callback ) ) {
  2284.         $filename call_user_func$unique_filename_callback$dir$name$ext );
  2285.     } else {
  2286.         $fname pathinfo$filenamePATHINFO_FILENAME );
  2287.         // Always append a number to file names that can potentially match image sub-size file names.
  2288.         if ( $fname && preg_match'/-(?:\d+x\d+|scaled|rotated)$/'$fname ) ) {
  2289.             $number 1;
  2290.             // At this point the file name may not be unique. This is tested below and the $number is incremented.
  2291.             $filename str_replace"{$fname}{$ext}""{$fname}-{$number}{$ext}"$filename );
  2292.         }
  2293.         /*
  2294.          * Get the mime type. Uploaded files were already checked with wp_check_filetype_and_ext()
  2295.          * in _wp_handle_upload(). Using wp_check_filetype() would be sufficient here.
  2296.          */
  2297.         $file_type wp_check_filetype$filename );
  2298.         $mime_type $file_type['type'];
  2299.         $is_image    = ( ! empty( $mime_type ) && str_starts_with$mime_type'image/' ) );
  2300.         $upload_dir  wp_get_upload_dir();
  2301.         $lc_filename null;
  2302.         $lc_ext strtolower$ext );
  2303.         $_dir   trailingslashit$dir );
  2304.         /*
  2305.          * If the extension is uppercase add an alternate file name with lowercase extension.
  2306.          * Both need to be tested for uniqueness as the extension will be changed to lowercase
  2307.          * for better compatibility with different filesystems. Fixes an inconsistency in WP < 2.9
  2308.          * where uppercase extensions were allowed but image sub-sizes were created with
  2309.          * lowercase extensions.
  2310.          */
  2311.         if ( $ext && $lc_ext !== $ext ) {
  2312.             $lc_filename preg_replace'|' preg_quote$ext ) . '$|'$lc_ext$filename );
  2313.         }
  2314.         /*
  2315.          * Increment the number added to the file name if there are any files in $dir
  2316.          * whose names match one of the possible name variations.
  2317.          */
  2318.         while ( file_exists$_dir $filename ) || ( $lc_filename && file_exists$_dir $lc_filename ) ) ) {
  2319.             $new_number = (int) $number 1;
  2320.             if ( $lc_filename ) {
  2321.                 $lc_filename str_replace(
  2322.                     array( "-{$number}{$lc_ext}""{$number}{$lc_ext}),
  2323.                     "-{$new_number}{$lc_ext}",
  2324.                     $lc_filename
  2325.                 );
  2326.             }
  2327.             if ( '' === "{$number}{$ext}) {
  2328.                 $filename "{$filename}-{$new_number}";
  2329.             } else {
  2330.                 $filename str_replace(
  2331.                     array( "-{$number}{$ext}""{$number}{$ext}),
  2332.                     "-{$new_number}{$ext}",
  2333.                     $filename
  2334.                 );
  2335.             }
  2336.             $number $new_number;
  2337.         }
  2338.         // Change the extension to lowercase if needed.
  2339.         if ( $lc_filename ) {
  2340.             $filename $lc_filename;
  2341.         }
  2342.         /*
  2343.          * Prevent collisions with existing file names that contain dimension-like strings
  2344.          * (whether they are subsizes or originals uploaded prior to #42437).
  2345.          */
  2346.         $files = array();
  2347.         $count 10000;
  2348.         // The (resized) image files would have name and extension, and will be in the uploads dir.
  2349.         if ( $name && $ext && @is_dir$dir ) && str_contains$dir$upload_dir['basedir'] ) ) {
  2350.             /**
  2351.              * Filters the file list used for calculating a unique filename for a newly added file.
  2352.              *
  2353.              * Returning an array from the filter will effectively short-circuit retrieval
  2354.              * from the filesystem and return the passed value instead.
  2355.              *
  2356.              * @since 5.5.0
  2357.              *
  2358.              * @param array|null $files    The list of files to use for filename comparisons.
  2359.              *                             Default null (to retrieve the list from the filesystem).
  2360.              * @param string     $dir      The directory for the new file.
  2361.              * @param string     $filename The proposed filename for the new file.
  2362.              */
  2363.             $files apply_filters'pre_wp_unique_filename_file_list'null$dir$filename );
  2364.             if ( null === $files ) {
  2365.                 // List of all files and directories contained in $dir.
  2366.                 $files = @scandir$dir );
  2367.             }
  2368.             if ( ! empty( $files ) ) {
  2369.                 // Remove "dot" dirs.
  2370.                 $files array_diff$files, array( '.''..' ) );
  2371.             }
  2372.             if ( ! empty( $files ) ) {
  2373.                 $count count$files );
  2374.                 /*
  2375.                  * Ensure this never goes into infinite loop as it uses pathinfo() and regex in the check,
  2376.                  * but string replacement for the changes.
  2377.                  */
  2378.                 $i 0;
  2379.                 while ( $i <= $count && _wp_check_existing_file_names$filename$files ) ) {
  2380.                     $new_number = (int) $number 1;
  2381.                     // If $ext is uppercase it was replaced with the lowercase version after the previous loop.
  2382.                     $filename str_replace(
  2383.                         array( "-{$number}{$lc_ext}""{$number}{$lc_ext}),
  2384.                         "-{$new_number}{$lc_ext}",
  2385.                         $filename
  2386.                     );
  2387.                     $number $new_number;
  2388.                     ++$i;
  2389.                 }
  2390.             }
  2391.         }
  2392.         /*
  2393.          * Check if an image will be converted after uploading or some existing image sub-size file names may conflict
  2394.          * when regenerated. If yes, ensure the new file name will be unique and will produce unique sub-sizes.
  2395.          */
  2396.         if ( $is_image ) {
  2397.             $output_formats wp_get_image_editor_output_format$_dir $filename$mime_type );
  2398.             $alt_types      = array();
  2399.             if ( ! empty( $output_formats$mime_type ] ) ) {
  2400.                 // The image will be converted to this format/mime type.
  2401.                 $alt_mime_type $output_formats$mime_type ];
  2402.                 // Other types of images whose names may conflict if their sub-sizes are regenerated.
  2403.                 $alt_types   array_keysarray_intersect$output_formats, array( $mime_type$alt_mime_type ) ) );
  2404.                 $alt_types[] = $alt_mime_type;
  2405.             } elseif ( ! empty( $output_formats ) ) {
  2406.                 $alt_types array_keysarray_intersect$output_formats, array( $mime_type ) ) );
  2407.             }
  2408.             // Remove duplicates and the original mime type. It will be added later if needed.
  2409.             $alt_types array_uniquearray_diff$alt_types, array( $mime_type ) ) );
  2410.             foreach ( $alt_types as $alt_type ) {
  2411.                 $alt_ext wp_get_default_extension_for_mime_type$alt_type );
  2412.                 if ( ! $alt_ext ) {
  2413.                     continue;
  2414.                 }
  2415.                 $alt_ext      ".{$alt_ext}";
  2416.                 $alt_filename preg_replace'|' preg_quote$lc_ext ) . '$|'$alt_ext$filename );
  2417.                 $alt_filenames$alt_ext ] = $alt_filename;
  2418.             }
  2419.             if ( ! empty( $alt_filenames ) ) {
  2420.                 /*
  2421.                  * Add the original filename. It needs to be checked again
  2422.                  * together with the alternate filenames when $number is incremented.
  2423.                  */
  2424.                 $alt_filenames$lc_ext ] = $filename;
  2425.                 // Ensure no infinite loop.
  2426.                 $i 0;
  2427.                 while ( $i <= $count && _wp_check_alternate_file_names$alt_filenames$_dir$files ) ) {
  2428.                     $new_number = (int) $number 1;
  2429.                     foreach ( $alt_filenames as $alt_ext => $alt_filename ) {
  2430.                         $alt_filenames$alt_ext ] = str_replace(
  2431.                             array( "-{$number}{$alt_ext}""{$number}{$alt_ext}),
  2432.                             "-{$new_number}{$alt_ext}",
  2433.                             $alt_filename
  2434.                         );
  2435.                     }
  2436.                     /*
  2437.                      * Also update the $number in (the output) $filename.
  2438.                      * If the extension was uppercase it was already replaced with the lowercase version.
  2439.                      */
  2440.                     $filename str_replace(
  2441.                         array( "-{$number}{$lc_ext}""{$number}{$lc_ext}),
  2442.                         "-{$new_number}{$lc_ext}",
  2443.                         $filename
  2444.                     );
  2445.                     $number $new_number;
  2446.                     ++$i;
  2447.                 }
  2448.             }
  2449.         }
  2450.     }
  2451.     /**
  2452.      * Filters the result when generating a unique file name.
  2453.      *
  2454.      * @since 4.5.0
  2455.      * @since 5.8.1 The `$alt_filenames` and `$number` parameters were added.
  2456.      *
  2457.      * @param string        $filename                 Unique file name.
  2458.      * @param string        $ext                      File extension. Example: ".png".
  2459.      * @param string        $dir                      Directory path.
  2460.      * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
  2461.      * @param string[]      $alt_filenames            Array of alternate file names that were checked for collisions.
  2462.      * @param int|string    $number                   The highest number that was used to make the file name unique
  2463.      *                                                or an empty string if unused.
  2464.      */
  2465.     return apply_filters'wp_unique_filename'$filename$ext$dir$unique_filename_callback$alt_filenames$number );
  2466. }
  2467. /**
  2468.  * Helper function to test if each of an array of file names could conflict with existing files.
  2469.  *
  2470.  * @since 5.8.1
  2471.  * @access private
  2472.  *
  2473.  * @param string[] $filenames Array of file names to check.
  2474.  * @param string   $dir       The directory containing the files.
  2475.  * @param array    $files     An array of existing files in the directory. May be empty.
  2476.  * @return bool True if the tested file name could match an existing file, false otherwise.
  2477.  */
  2478. function _wp_check_alternate_file_names$filenames$dir$files ) {
  2479.     foreach ( $filenames as $filename ) {
  2480.         if ( file_exists$dir $filename ) ) {
  2481.             return true;
  2482.         }
  2483.         if ( ! empty( $files ) && _wp_check_existing_file_names$filename$files ) ) {
  2484.             return true;
  2485.         }
  2486.     }
  2487.     return false;
  2488. }
  2489. /**
  2490.  * Helper function to check if a file name could match an existing image sub-size file name.
  2491.  *
  2492.  * @since 5.3.1
  2493.  * @access private
  2494.  *
  2495.  * @param string $filename The file name to check.
  2496.  * @param array  $files    An array of existing files in the directory.
  2497.  * @return bool True if the tested file name could match an existing file, false otherwise.
  2498.  */
  2499. function _wp_check_existing_file_names$filename$files ) {
  2500.     $fname pathinfo$filenamePATHINFO_FILENAME );
  2501.     $ext   pathinfo$filenamePATHINFO_EXTENSION );
  2502.     // Edge case, file names like `.ext`.
  2503.     if ( empty( $fname ) ) {
  2504.         return false;
  2505.     }
  2506.     if ( $ext ) {
  2507.         $ext ".$ext";
  2508.     }
  2509.     $regex '/^' preg_quote$fname ) . '-(?:\d+x\d+|scaled|rotated)' preg_quote$ext ) . '$/i';
  2510.     foreach ( $files as $file ) {
  2511.         if ( preg_match$regex$file ) ) {
  2512.             return true;
  2513.         }
  2514.     }
  2515.     return false;
  2516. }
  2517. /**
  2518.  * Creates a file in the upload folder with given content.
  2519.  *
  2520.  * If there is an error, then the key 'error' will exist with the error message.
  2521.  * If success, then the key 'file' will have the unique file path, the 'url' key
  2522.  * will have the link to the new file. and the 'error' key will be set to false.
  2523.  *
  2524.  * This function will not move an uploaded file to the upload folder. It will
  2525.  * create a new file with the content in $bits parameter. If you move the upload
  2526.  * file, read the content of the uploaded file, and then you can give the
  2527.  * filename and content to this function, which will add it to the upload
  2528.  * folder.
  2529.  *
  2530.  * The permissions will be set on the new file automatically by this function.
  2531.  *
  2532.  * @since 2.0.0
  2533.  *
  2534.  * @param string      $name       Filename.
  2535.  * @param null|string $deprecated Never used. Set to null.
  2536.  * @param string      $bits       File content
  2537.  * @param string|null $time       Optional. Time formatted in 'yyyy/mm'. Default null.
  2538.  * @return array {
  2539.  *     Information about the newly-uploaded file.
  2540.  *
  2541.  *     @type string       $file  Filename of the newly-uploaded file.
  2542.  *     @type string       $url   URL of the uploaded file.
  2543.  *     @type string       $type  File type.
  2544.  *     @type string|false $error Error message, if there has been an error.
  2545.  * }
  2546.  */
  2547. function wp_upload_bits$name$deprecated$bits$time null ) {
  2548.     if ( ! empty( $deprecated ) ) {
  2549.         _deprecated_argument__FUNCTION__'2.0.0' );
  2550.     }
  2551.     if ( empty( $name ) ) {
  2552.         return array( 'error' => __'Empty filename' ) );
  2553.     }
  2554.     $wp_filetype wp_check_filetype$name );
  2555.     if ( ! $wp_filetype['ext'] && ! current_user_can'unfiltered_upload' ) ) {
  2556.         return array( 'error' => __'Sorry, you are not allowed to upload this file type.' ) );
  2557.     }
  2558.     $upload wp_upload_dir$time );
  2559.     if ( false !== $upload['error'] ) {
  2560.         return $upload;
  2561.     }
  2562.     /**
  2563.      * Filters whether to treat the upload bits as an error.
  2564.      *
  2565.      * Returning a non-array from the filter will effectively short-circuit preparing the upload bits
  2566.      * and return that value instead. An error message should be returned as a string.
  2567.      *
  2568.      * @since 3.0.0
  2569.      *
  2570.      * @param array|string $upload_bits_error An array of upload bits data, or error message to return.
  2571.      */
  2572.     $upload_bits_error apply_filters(
  2573.         'wp_upload_bits',
  2574.         array(
  2575.             'name' => $name,
  2576.             'bits' => $bits,
  2577.             'time' => $time,
  2578.         )
  2579.     );
  2580.     if ( ! is_array$upload_bits_error ) ) {
  2581.         $upload['error'] = $upload_bits_error;
  2582.         return $upload;
  2583.     }
  2584.     $filename wp_unique_filename$upload['path'], $name );
  2585.     $new_file $upload['path'] . "/$filename";
  2586.     if ( ! wp_mkdir_pdirname$new_file ) ) ) {
  2587.         if ( str_starts_with$upload['basedir'], ABSPATH ) ) {
  2588.             $error_path str_replaceABSPATH''$upload['basedir'] ) . $upload['subdir'];
  2589.         } else {
  2590.             $error_path wp_basename$upload['basedir'] ) . $upload['subdir'];
  2591.         }
  2592.         $message sprintf(
  2593.             /* translators: %s: Directory path. */
  2594.             __'Unable to create directory %s. Is its parent directory writable by the server?' ),
  2595.             $error_path
  2596.         );
  2597.         return array( 'error' => $message );
  2598.     }
  2599.     $ifp = @fopen$new_file'wb' );
  2600.     if ( ! $ifp ) {
  2601.         return array(
  2602.             /* translators: %s: File name. */
  2603.             'error' => sprintf__'Could not write file %s' ), $new_file ),
  2604.         );
  2605.     }
  2606.     fwrite$ifp$bits );
  2607.     fclose$ifp );
  2608.     clearstatcache();
  2609.     // Set correct file permissions.
  2610.     $stat  = @ statdirname$new_file ) );
  2611.     $perms $stat['mode'] & 0007777;
  2612.     $perms $perms 0000666;
  2613.     chmod$new_file$perms );
  2614.     clearstatcache();
  2615.     // Compute the URL.
  2616.     $url $upload['url'] . "/$filename";
  2617.     if ( is_multisite() ) {
  2618.         clean_dirsize_cache$new_file );
  2619.     }
  2620.     /** This filter is documented in wp-admin/includes/file.php */
  2621.     return apply_filters(
  2622.         'wp_handle_upload',
  2623.         array(
  2624.             'file'  => $new_file,
  2625.             'url'   => $url,
  2626.             'type'  => $wp_filetype['type'],
  2627.             'error' => false,
  2628.         ),
  2629.         'sideload'
  2630.     );
  2631. }
  2632. /**
  2633.  * Retrieves the file type based on the extension name.
  2634.  *
  2635.  * @since 2.5.0
  2636.  *
  2637.  * @param string $ext The extension to search.
  2638.  * @return string|void The file type, example: audio, video, document, spreadsheet, etc.
  2639.  */
  2640. function wp_ext2type$ext ) {
  2641.     $ext strtolower$ext );
  2642.     $ext2type wp_get_ext_types();
  2643.     foreach ( $ext2type as $type => $exts ) {
  2644.         if ( in_array$ext$extstrue ) ) {
  2645.             return $type;
  2646.         }
  2647.     }
  2648. }
  2649. /**
  2650.  * Returns first matched extension for the mime-type,
  2651.  * as mapped from wp_get_mime_types().
  2652.  *
  2653.  * @since 5.8.1
  2654.  *
  2655.  * @param string $mime_type
  2656.  *
  2657.  * @return string|false
  2658.  */
  2659. function wp_get_default_extension_for_mime_type$mime_type ) {
  2660.     $extensions explode'|'array_search$mime_typewp_get_mime_types(), true ) );
  2661.     if ( empty( $extensions[0] ) ) {
  2662.         return false;
  2663.     }
  2664.     return $extensions[0];
  2665. }
  2666. /**
  2667.  * Retrieves the file type from the file name.
  2668.  *
  2669.  * You can optionally define the mime array, if needed.
  2670.  *
  2671.  * @since 2.0.4
  2672.  *
  2673.  * @param string        $filename File name or path.
  2674.  * @param string[]|null $mimes    Optional. Array of allowed mime types keyed by their file extension regex.
  2675.  *                                Defaults to the result of get_allowed_mime_types().
  2676.  * @return array {
  2677.  *     Values for the extension and mime type.
  2678.  *
  2679.  *     @type string|false $ext  File extension, or false if the file doesn't match a mime type.
  2680.  *     @type string|false $type File mime type, or false if the file doesn't match a mime type.
  2681.  * }
  2682.  */
  2683. function wp_check_filetype$filename$mimes null ) {
  2684.     if ( empty( $mimes ) ) {
  2685.         $mimes get_allowed_mime_types();
  2686.     }
  2687.     $type false;
  2688.     $ext  false;
  2689.     foreach ( $mimes as $ext_preg => $mime_match ) {
  2690.         $ext_preg '!\.(' $ext_preg ')$!i';
  2691.         if ( preg_match$ext_preg$filename$ext_matches ) ) {
  2692.             $type $mime_match;
  2693.             $ext  $ext_matches[1];
  2694.             break;
  2695.         }
  2696.     }
  2697.     return compact'ext''type' );
  2698. }
  2699. /**
  2700.  * Attempts to determine the real file type of a file.
  2701.  *
  2702.  * If unable to, the file name extension will be used to determine type.
  2703.  *
  2704.  * If it's determined that the extension does not match the file's real type,
  2705.  * then the "proper_filename" value will be set with a proper filename and extension.
  2706.  *
  2707.  * Currently this function only supports renaming images validated via wp_get_image_mime().
  2708.  *
  2709.  * @since 3.0.0
  2710.  *
  2711.  * @param string        $file     Full path to the file.
  2712.  * @param string        $filename The name of the file (may differ from $file due to $file being
  2713.  *                                in a tmp directory).
  2714.  * @param string[]|null $mimes    Optional. Array of allowed mime types keyed by their file extension regex.
  2715.  *                                Defaults to the result of get_allowed_mime_types().
  2716.  * @return array {
  2717.  *     Values for the extension, mime type, and corrected filename.
  2718.  *
  2719.  *     @type string|false $ext             File extension, or false if the file doesn't match a mime type.
  2720.  *     @type string|false $type            File mime type, or false if the file doesn't match a mime type.
  2721.  *     @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
  2722.  * }
  2723.  */
  2724. function wp_check_filetype_and_ext$file$filename$mimes null ) {
  2725.     $proper_filename false;
  2726.     // Do basic extension validation and MIME mapping.
  2727.     $wp_filetype wp_check_filetype$filename$mimes );
  2728.     $ext         $wp_filetype['ext'];
  2729.     $type        $wp_filetype['type'];
  2730.     // We can't do any further validation without a file to work with.
  2731.     if ( ! file_exists$file ) ) {
  2732.         return compact'ext''type''proper_filename' );
  2733.     }
  2734.     $real_mime false;
  2735.     // Validate image types.
  2736.     if ( $type && str_starts_with$type'image/' ) ) {
  2737.         // Attempt to figure out what type of image it actually is.
  2738.         $real_mime wp_get_image_mime$file );
  2739.         $heic_images_extensions = array(
  2740.             'heif',
  2741.             'heics',
  2742.             'heifs',
  2743.         );
  2744.         if ( $real_mime && ( $real_mime !== $type || in_array$ext$heic_images_extensionstrue ) ) ) {
  2745.             /**
  2746.              * Filters the list mapping image mime types to their respective extensions.
  2747.              *
  2748.              * @since 3.0.0
  2749.              *
  2750.              * @param array $mime_to_ext Array of image mime types and their matching extensions.
  2751.              */
  2752.             $mime_to_ext apply_filters(
  2753.                 'getimagesize_mimes_to_exts',
  2754.                 array(
  2755.                     'image/jpeg'          => 'jpg',
  2756.                     'image/png'           => 'png',
  2757.                     'image/gif'           => 'gif',
  2758.                     'image/bmp'           => 'bmp',
  2759.                     'image/tiff'          => 'tif',
  2760.                     'image/webp'          => 'webp',
  2761.                     'image/avif'          => 'avif',
  2762.                     /*
  2763.                      * In theory there are/should be file extensions that correspond to the
  2764.                      * mime types: .heif, .heics and .heifs. However it seems that HEIC images
  2765.                      * with any of the mime types commonly have a .heic file extension.
  2766.                      * Seems keeping the status quo here is best for compatibility.
  2767.                      */
  2768.                     'image/heic'          => 'heic',
  2769.                     'image/heif'          => 'heic',
  2770.                     'image/heic-sequence' => 'heic',
  2771.                     'image/heif-sequence' => 'heic',
  2772.                 )
  2773.             );
  2774.             // Replace whatever is after the last period in the filename with the correct extension.
  2775.             if ( ! empty( $mime_to_ext$real_mime ] ) ) {
  2776.                 $filename_parts explode'.'$filename );
  2777.                 array_pop$filename_parts );
  2778.                 $filename_parts[] = $mime_to_ext$real_mime ];
  2779.                 $new_filename     implode'.'$filename_parts );
  2780.                 if ( $new_filename !== $filename ) {
  2781.                     $proper_filename $new_filename// Mark that it changed.
  2782.                 }
  2783.                 // Redefine the extension / MIME.
  2784.                 $wp_filetype wp_check_filetype$new_filename$mimes );
  2785.                 $ext         $wp_filetype['ext'];
  2786.                 $type        $wp_filetype['type'];
  2787.             } else {
  2788.                 // Reset $real_mime and try validating again.
  2789.                 $real_mime false;
  2790.             }
  2791.         }
  2792.     }
  2793.     // Validate files that didn't get validated during previous checks.
  2794.     if ( $type && ! $real_mime && extension_loaded'fileinfo' ) ) {
  2795.         $finfo     finfo_openFILEINFO_MIME_TYPE );
  2796.         $real_mime finfo_file$finfo$file );
  2797.         finfo_close$finfo );
  2798.         $google_docs_types = array(
  2799.             'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  2800.             'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  2801.         );
  2802.         foreach ( $google_docs_types as $google_docs_type ) {
  2803.             /*
  2804.              * finfo_file() can return duplicate mime type for Google docs,
  2805.              * this conditional reduces it to a single instance.
  2806.              *
  2807.              * @see https://bugs.php.net/bug.php?id=77784
  2808.              * @see https://core.trac.wordpress.org/ticket/57898
  2809.              */
  2810.             if ( === substr_count$real_mime$google_docs_type ) ) {
  2811.                 $real_mime $google_docs_type;
  2812.             }
  2813.         }
  2814.         // fileinfo often misidentifies obscure files as one of these types.
  2815.         $nonspecific_types = array(
  2816.             'application/octet-stream',
  2817.             'application/encrypted',
  2818.             'application/CDFV2-encrypted',
  2819.             'application/zip',
  2820.         );
  2821.         /*
  2822.          * If $real_mime doesn't match the content type we're expecting from the file's extension,
  2823.          * we need to do some additional vetting. Media types and those listed in $nonspecific_types are
  2824.          * allowed some leeway, but anything else must exactly match the real content type.
  2825.          */
  2826.         if ( in_array$real_mime$nonspecific_typestrue ) ) {
  2827.             // File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
  2828.             if ( ! in_arraysubstr$type0strcspn$type'/' ) ), array( 'application''video''audio' ), true ) ) {
  2829.                 $type false;
  2830.                 $ext  false;
  2831.             }
  2832.         } elseif ( str_starts_with$real_mime'video/' ) || str_starts_with$real_mime'audio/' ) ) {
  2833.             /*
  2834.              * For these types, only the major type must match the real value.
  2835.              * This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
  2836.              * and some media files are commonly named with the wrong extension (.mov instead of .mp4)
  2837.              */
  2838.             if ( substr$real_mime0strcspn$real_mime'/' ) ) !== substr$type0strcspn$type'/' ) ) ) {
  2839.                 $type false;
  2840.                 $ext  false;
  2841.             }
  2842.         } elseif ( 'text/plain' === $real_mime ) {
  2843.             // A few common file types are occasionally detected as text/plain; allow those.
  2844.             if ( ! in_array(
  2845.                 $type,
  2846.                 array(
  2847.                     'text/plain',
  2848.                     'text/csv',
  2849.                     'application/csv',
  2850.                     'text/richtext',
  2851.                     'text/tsv',
  2852.                     'text/vtt',
  2853.                 ),
  2854.                 true
  2855.             )
  2856.             ) {
  2857.                 $type false;
  2858.                 $ext  false;
  2859.             }
  2860.         } elseif ( 'application/csv' === $real_mime ) {
  2861.             // Special casing for CSV files.
  2862.             if ( ! in_array(
  2863.                 $type,
  2864.                 array(
  2865.                     'text/csv',
  2866.                     'text/plain',
  2867.                     'application/csv',
  2868.                 ),
  2869.                 true
  2870.             )
  2871.             ) {
  2872.                 $type false;
  2873.                 $ext  false;
  2874.             }
  2875.         } elseif ( 'text/rtf' === $real_mime ) {
  2876.             // Special casing for RTF files.
  2877.             if ( ! in_array(
  2878.                 $type,
  2879.                 array(
  2880.                     'text/rtf',
  2881.                     'text/plain',
  2882.                     'application/rtf',
  2883.                 ),
  2884.                 true
  2885.             )
  2886.             ) {
  2887.                 $type false;
  2888.                 $ext  false;
  2889.             }
  2890.         } else {
  2891.             if ( $type !== $real_mime ) {
  2892.                 /*
  2893.                  * Everything else including image/* and application/*:
  2894.                  * If the real content type doesn't match the file extension, assume it's dangerous.
  2895.                  */
  2896.                 $type false;
  2897.                 $ext  false;
  2898.             }
  2899.         }
  2900.     }
  2901.     // The mime type must be allowed.
  2902.     if ( $type ) {
  2903.         $allowed get_allowed_mime_types();
  2904.         if ( ! in_array$type$allowedtrue ) ) {
  2905.             $type false;
  2906.             $ext  false;
  2907.         }
  2908.     }
  2909.     /**
  2910.      * Filters the "real" file type of the given file.
  2911.      *
  2912.      * @since 3.0.0
  2913.      * @since 5.1.0 The $real_mime parameter was added.
  2914.      *
  2915.      * @param array         $wp_check_filetype_and_ext {
  2916.      *     Values for the extension, mime type, and corrected filename.
  2917.      *
  2918.      *     @type string|false $ext             File extension, or false if the file doesn't match a mime type.
  2919.      *     @type string|false $type            File mime type, or false if the file doesn't match a mime type.
  2920.      *     @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
  2921.      * }
  2922.      * @param string        $file                      Full path to the file.
  2923.      * @param string        $filename                  The name of the file (may differ from $file due to
  2924.      *                                                 $file being in a tmp directory).
  2925.      * @param string[]|null $mimes                     Array of mime types keyed by their file extension regex, or null if
  2926.      *                                                 none were provided.
  2927.      * @param string|false  $real_mime                 The actual mime type or false if the type cannot be determined.
  2928.      */
  2929.     return apply_filters'wp_check_filetype_and_ext'compact'ext''type''proper_filename' ), $file$filename$mimes$real_mime );
  2930. }
  2931. /**
  2932.  * Returns the real mime type of an image file.
  2933.  *
  2934.  * This depends on exif_imagetype() or getimagesize() to determine real mime types.
  2935.  *
  2936.  * @since 4.7.1
  2937.  * @since 5.8.0 Added support for WebP images.
  2938.  * @since 6.5.0 Added support for AVIF images.
  2939.  * @since 6.7.0 Added support for HEIC images.
  2940.  *
  2941.  * @param string $file Full path to the file.
  2942.  * @return string|false The actual mime type or false if the type cannot be determined.
  2943.  */
  2944. function wp_get_image_mime$file ) {
  2945.     /*
  2946.      * Use exif_imagetype() to check the mimetype if available or fall back to
  2947.      * getimagesize() if exif isn't available. If either function throws an Exception
  2948.      * we assume the file could not be validated.
  2949.      */
  2950.     try {
  2951.         if ( is_callable'exif_imagetype' ) ) {
  2952.             $imagetype exif_imagetype$file );
  2953.             $mime      = ( $imagetype ) ? image_type_to_mime_type$imagetype ) : false;
  2954.         } elseif ( function_exists'getimagesize' ) ) {
  2955.             // Don't silence errors when in debug mode, unless running unit tests.
  2956.             if ( defined'WP_DEBUG' ) && WP_DEBUG && ! defined'WP_RUN_CORE_TESTS' ) ) {
  2957.                 // Not using wp_getimagesize() here to avoid an infinite loop.
  2958.                 $imagesize getimagesize$file );
  2959.             } else {
  2960.                 $imagesize = @getimagesize$file );
  2961.             }
  2962.             $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
  2963.         } else {
  2964.             $mime false;
  2965.         }
  2966.         if ( false !== $mime ) {
  2967.             return $mime;
  2968.         }
  2969.         $magic file_get_contents$filefalsenull012 );
  2970.         if ( false === $magic ) {
  2971.             return false;
  2972.         }
  2973.         /*
  2974.          * Add WebP fallback detection when image library doesn't support WebP.
  2975.          * Note: detection values come from LibWebP, see
  2976.          * https://github.com/webmproject/libwebp/blob/master/imageio/image_dec.c#L30
  2977.          */
  2978.         $magic bin2hex$magic );
  2979.         if (
  2980.             // RIFF.
  2981.             str_starts_with$magic'52494646' ) ) &&
  2982.             // WEBP.
  2983.             16 === strpos$magic'57454250' ) )
  2984.         ) {
  2985.             $mime 'image/webp';
  2986.         }
  2987.         /**
  2988.          * Add AVIF fallback detection when image library doesn't support AVIF.
  2989.          *
  2990.          * Detection based on section 4.3.1 File-type box definition of the ISO/IEC 14496-12
  2991.          * specification and the AV1-AVIF spec, see https://aomediacodec.github.io/av1-avif/v1.1.0.html#brands.
  2992.          */
  2993.         // Divide the header string into 4 byte groups.
  2994.         $magic str_split$magic);
  2995.         if ( isset( $magic[1] ) && isset( $magic[2] ) && 'ftyp' === hex2bin$magic[1] ) ) {
  2996.             if ( 'avif' === hex2bin$magic[2] ) || 'avis' === hex2bin$magic[2] ) ) {
  2997.                 $mime 'image/avif';
  2998.             } elseif ( 'heic' === hex2bin$magic[2] ) ) {
  2999.                 $mime 'image/heic';
  3000.             } elseif ( 'heif' === hex2bin$magic[2] ) ) {
  3001.                 $mime 'image/heif';
  3002.             } else {
  3003.                 /*
  3004.                  * HEIC/HEIF images and image sequences/animations may have other strings here
  3005.                  * like mif1, msf1, etc. For now fall back to using finfo_file() to detect these.
  3006.                  */
  3007.                 if ( extension_loaded'fileinfo' ) ) {
  3008.                     $fileinfo  finfo_openFILEINFO_MIME_TYPE );
  3009.                     $mime_type finfo_file$fileinfo$file );
  3010.                     finfo_close$fileinfo );
  3011.                     if ( wp_is_heic_image_mime_type$mime_type ) ) {
  3012.                         $mime $mime_type;
  3013.                     }
  3014.                 }
  3015.             }
  3016.         }
  3017.     } catch ( Exception $e ) {
  3018.         $mime false;
  3019.     }
  3020.     return $mime;
  3021. }
  3022. /**
  3023.  * Retrieves the list of mime types and file extensions.
  3024.  *
  3025.  * @since 3.5.0
  3026.  * @since 4.2.0 Support was added for GIMP (.xcf) files.
  3027.  * @since 4.9.2 Support was added for Flac (.flac) files.
  3028.  * @since 4.9.6 Support was added for AAC (.aac) files.
  3029.  * @since 6.8.0 Support was added for `audio/x-wav`.
  3030.  *
  3031.  * @return string[] Array of mime types keyed by the file extension regex corresponding to those types.
  3032.  */
  3033. function wp_get_mime_types() {
  3034.     /**
  3035.      * Filters the list of mime types and file extensions.
  3036.      *
  3037.      * This filter should be used to add, not remove, mime types. To remove
  3038.      * mime types, use the {@see 'upload_mimes'} filter.
  3039.      *
  3040.      * @since 3.5.0
  3041.      *
  3042.      * @param string[] $wp_get_mime_types Mime types keyed by the file extension regex
  3043.      *                                    corresponding to those types.
  3044.      */
  3045.     return apply_filters(
  3046.         'mime_types',
  3047.         array(
  3048.             // Image formats.
  3049.             'jpg|jpeg|jpe'                 => 'image/jpeg',
  3050.             'gif'                          => 'image/gif',
  3051.             'png'                          => 'image/png',
  3052.             'bmp'                          => 'image/bmp',
  3053.             'tiff|tif'                     => 'image/tiff',
  3054.             'webp'                         => 'image/webp',
  3055.             'avif'                         => 'image/avif',
  3056.             'ico'                          => 'image/x-icon',
  3057.             // TODO: Needs improvement. All images with the following mime types seem to have .heic file extension.
  3058.             'heic'                         => 'image/heic',
  3059.             'heif'                         => 'image/heif',
  3060.             'heics'                        => 'image/heic-sequence',
  3061.             'heifs'                        => 'image/heif-sequence',
  3062.             // Video formats.
  3063.             'asf|asx'                      => 'video/x-ms-asf',
  3064.             'wmv'                          => 'video/x-ms-wmv',
  3065.             'wmx'                          => 'video/x-ms-wmx',
  3066.             'wm'                           => 'video/x-ms-wm',
  3067.             'avi'                          => 'video/avi',
  3068.             'divx'                         => 'video/divx',
  3069.             'flv'                          => 'video/x-flv',
  3070.             'mov|qt'                       => 'video/quicktime',
  3071.             'mpeg|mpg|mpe'                 => 'video/mpeg',
  3072.             'mp4|m4v'                      => 'video/mp4',
  3073.             'ogv'                          => 'video/ogg',
  3074.             'webm'                         => 'video/webm',
  3075.             'mkv'                          => 'video/x-matroska',
  3076.             '3gp|3gpp'                     => 'video/3gpp',  // Can also be audio.
  3077.             '3g2|3gp2'                     => 'video/3gpp2'// Can also be audio.
  3078.             // Text formats.
  3079.             'txt|asc|c|cc|h|srt'           => 'text/plain',
  3080.             'csv'                          => 'text/csv',
  3081.             'tsv'                          => 'text/tab-separated-values',
  3082.             'ics'                          => 'text/calendar',
  3083.             'rtx'                          => 'text/richtext',
  3084.             'css'                          => 'text/css',
  3085.             'htm|html'                     => 'text/html',
  3086.             'vtt'                          => 'text/vtt',
  3087.             'dfxp'                         => 'application/ttaf+xml',
  3088.             // Audio formats.
  3089.             'mp3|m4a|m4b'                  => 'audio/mpeg',
  3090.             'aac'                          => 'audio/aac',
  3091.             'ra|ram'                       => 'audio/x-realaudio',
  3092.             'wav|x-wav'                    => 'audio/wav',
  3093.             'ogg|oga'                      => 'audio/ogg',
  3094.             'flac'                         => 'audio/flac',
  3095.             'mid|midi'                     => 'audio/midi',
  3096.             'wma'                          => 'audio/x-ms-wma',
  3097.             'wax'                          => 'audio/x-ms-wax',
  3098.             'mka'                          => 'audio/x-matroska',
  3099.             // Misc application formats.
  3100.             'rtf'                          => 'application/rtf',
  3101.             'js'                           => 'application/javascript',
  3102.             'pdf'                          => 'application/pdf',
  3103.             'swf'                          => 'application/x-shockwave-flash',
  3104.             'class'                        => 'application/java',
  3105.             'tar'                          => 'application/x-tar',
  3106.             'zip'                          => 'application/zip',
  3107.             'gz|gzip'                      => 'application/x-gzip',
  3108.             'rar'                          => 'application/rar',
  3109.             '7z'                           => 'application/x-7z-compressed',
  3110.             'exe'                          => 'application/x-msdownload',
  3111.             'psd'                          => 'application/octet-stream',
  3112.             'xcf'                          => 'application/octet-stream',
  3113.             // MS Office formats.
  3114.             'doc'                          => 'application/msword',
  3115.             'pot|pps|ppt'                  => 'application/vnd.ms-powerpoint',
  3116.             'wri'                          => 'application/vnd.ms-write',
  3117.             'xla|xls|xlt|xlw'              => 'application/vnd.ms-excel',
  3118.             'mdb'                          => 'application/vnd.ms-access',
  3119.             'mpp'                          => 'application/vnd.ms-project',
  3120.             'docx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  3121.             'docm'                         => 'application/vnd.ms-word.document.macroEnabled.12',
  3122.             'dotx'                         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  3123.             'dotm'                         => 'application/vnd.ms-word.template.macroEnabled.12',
  3124.             'xlsx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  3125.             'xlsm'                         => 'application/vnd.ms-excel.sheet.macroEnabled.12',
  3126.             'xlsb'                         => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
  3127.             'xltx'                         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  3128.             'xltm'                         => 'application/vnd.ms-excel.template.macroEnabled.12',
  3129.             'xlam'                         => 'application/vnd.ms-excel.addin.macroEnabled.12',
  3130.             'pptx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  3131.             'pptm'                         => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
  3132.             'ppsx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  3133.             'ppsm'                         => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
  3134.             'potx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.template',
  3135.             'potm'                         => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
  3136.             'ppam'                         => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
  3137.             'sldx'                         => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
  3138.             'sldm'                         => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
  3139.             'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
  3140.             'oxps'                         => 'application/oxps',
  3141.             'xps'                          => 'application/vnd.ms-xpsdocument',
  3142.             // OpenOffice formats.
  3143.             'odt'                          => 'application/vnd.oasis.opendocument.text',
  3144.             'odp'                          => 'application/vnd.oasis.opendocument.presentation',
  3145.             'ods'                          => 'application/vnd.oasis.opendocument.spreadsheet',
  3146.             'odg'                          => 'application/vnd.oasis.opendocument.graphics',
  3147.             'odc'                          => 'application/vnd.oasis.opendocument.chart',
  3148.             'odb'                          => 'application/vnd.oasis.opendocument.database',
  3149.             'odf'                          => 'application/vnd.oasis.opendocument.formula',
  3150.             // WordPerfect formats.
  3151.             'wp|wpd'                       => 'application/wordperfect',
  3152.             // iWork formats.
  3153.             'key'                          => 'application/vnd.apple.keynote',
  3154.             'numbers'                      => 'application/vnd.apple.numbers',
  3155.             'pages'                        => 'application/vnd.apple.pages',
  3156.         )
  3157.     );
  3158. }
  3159. /**
  3160.  * Retrieves the list of common file extensions and their types.
  3161.  *
  3162.  * @since 4.6.0
  3163.  *
  3164.  * @return array[] Multi-dimensional array of file extensions types keyed by the type of file.
  3165.  */
  3166. function wp_get_ext_types() {
  3167.     /**
  3168.      * Filters file type based on the extension name.
  3169.      *
  3170.      * @since 2.5.0
  3171.      *
  3172.      * @see wp_ext2type()
  3173.      *
  3174.      * @param array[] $ext2type Multi-dimensional array of file extensions types keyed by the type of file.
  3175.      */
  3176.     return apply_filters(
  3177.         'ext2type',
  3178.         array(
  3179.             'image'       => array( 'jpg''jpeg''jpe''gif''png''bmp''tif''tiff''ico''heic''heif''webp''avif' ),
  3180.             'audio'       => array( 'aac''ac3''aif''aiff''flac''m3a''m4a''m4b''mka''mp1''mp2''mp3''ogg''oga''ram''wav''wma' ),
  3181.             'video'       => array( '3g2''3gp''3gpp''asf''avi''divx''dv''flv''m4v''mkv''mov''mp4''mpeg''mpg''mpv''ogm''ogv''qt''rm''vob''wmv' ),
  3182.             'document'    => array( 'doc''docx''docm''dotm''odt''pages''pdf''xps''oxps''rtf''wp''wpd''psd''xcf' ),
  3183.             'spreadsheet' => array( 'numbers''ods''xls''xlsx''xlsm''xlsb' ),
  3184.             'interactive' => array( 'swf''key''ppt''pptx''pptm''pps''ppsx''ppsm''sldx''sldm''odp' ),
  3185.             'text'        => array( 'asc''csv''tsv''txt' ),
  3186.             'archive'     => array( 'bz2''cab''dmg''gz''rar''sea''sit''sqx''tar''tgz''zip''7z' ),
  3187.             'code'        => array( 'css''htm''html''php''js' ),
  3188.         )
  3189.     );
  3190. }
  3191. /**
  3192.  * Wrapper for PHP filesize with filters and casting the result as an integer.
  3193.  *
  3194.  * @since 6.0.0
  3195.  *
  3196.  * @link https://www.php.net/manual/en/function.filesize.php
  3197.  *
  3198.  * @param string $path Path to the file.
  3199.  * @return int The size of the file in bytes, or 0 in the event of an error.
  3200.  */
  3201. function wp_filesize$path ) {
  3202.     /**
  3203.      * Filters the result of wp_filesize before the PHP function is run.
  3204.      *
  3205.      * @since 6.0.0
  3206.      *
  3207.      * @param null|int $size The unfiltered value. Returning an int from the callback bypasses the filesize call.
  3208.      * @param string   $path Path to the file.
  3209.      */
  3210.     $size apply_filters'pre_wp_filesize'null$path );
  3211.     if ( is_int$size ) ) {
  3212.         return $size;
  3213.     }
  3214.     $size file_exists$path ) ? (int) filesize$path ) : 0;
  3215.     /**
  3216.      * Filters the size of the file.
  3217.      *
  3218.      * @since 6.0.0
  3219.      *
  3220.      * @param int    $size The result of PHP filesize on the file.
  3221.      * @param string $path Path to the file.
  3222.      */
  3223.     return (int) apply_filters'wp_filesize'$size$path );
  3224. }
  3225. /**
  3226.  * Retrieves the list of allowed mime types and file extensions.
  3227.  *
  3228.  * @since 2.8.6
  3229.  *
  3230.  * @param int|WP_User $user Optional. User to check. Defaults to current user.
  3231.  * @return string[] Array of mime types keyed by the file extension regex corresponding
  3232.  *                  to those types.
  3233.  */
  3234. function get_allowed_mime_types$user null ) {
  3235.     $t wp_get_mime_types();
  3236.     unset( $t['swf'], $t['exe'] );
  3237.     if ( function_exists'current_user_can' ) ) {
  3238.         $unfiltered $user user_can$user'unfiltered_html' ) : current_user_can'unfiltered_html' );
  3239.     }
  3240.     if ( empty( $unfiltered ) ) {
  3241.         unset( $t['htm|html'], $t['js'] );
  3242.     }
  3243.     /**
  3244.      * Filters the list of allowed mime types and file extensions.
  3245.      *
  3246.      * @since 2.0.0
  3247.      *
  3248.      * @param array            $t    Mime types keyed by the file extension regex corresponding to those types.
  3249.      * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
  3250.      */
  3251.     return apply_filters'upload_mimes'$t$user );
  3252. }
  3253. /**
  3254.  * Displays "Are You Sure" message to confirm the action being taken.
  3255.  *
  3256.  * If the action has the nonce explain message, then it will be displayed
  3257.  * along with the "Are you sure?" message.
  3258.  *
  3259.  * @since 2.0.4
  3260.  *
  3261.  * @param string $action The nonce action.
  3262.  */
  3263. function wp_nonce_ays$action ) {
  3264.     // Default title and response code.
  3265.     $title         __'An error occurred.' );
  3266.     $response_code 403;
  3267.     if ( 'log-out' === $action ) {
  3268.         $title sprintf(
  3269.             /* translators: %s: Site title. */
  3270.             __'You are attempting to log out of %s' ),
  3271.             get_bloginfo'name' )
  3272.         );
  3273.         $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
  3274.         $html  $title;
  3275.         $html .= '</p><p>';
  3276.         $html .= sprintf(
  3277.             /* translators: %s: Logout URL. */
  3278.             __'Do you really want to <a href="%s">log out</a>?' ),
  3279.             wp_logout_url$redirect_to )
  3280.         );
  3281.     } else {
  3282.         $html __'The link you followed has expired.' );
  3283.         if ( wp_get_referer() ) {
  3284.             $wp_http_referer remove_query_arg'updated'wp_get_referer() );
  3285.             $wp_http_referer wp_validate_redirectsanitize_url$wp_http_referer ) );
  3286.             $html .= '</p><p>';
  3287.             $html .= sprintf(
  3288.                 '<a href="%s">%s</a>',
  3289.                 esc_url$wp_http_referer ),
  3290.                 __'Please try again.' )
  3291.             );
  3292.         }
  3293.     }
  3294.     wp_die$html$title$response_code );
  3295. }
  3296. /**
  3297.  * Kills WordPress execution and displays HTML page with an error message.
  3298.  *
  3299.  * This function complements the `die()` PHP function. The difference is that
  3300.  * HTML will be displayed to the user. It is recommended to use this function
  3301.  * only when the execution should not continue any further. It is not recommended
  3302.  * to call this function very often, and try to handle as many errors as possible
  3303.  * silently or more gracefully.
  3304.  *
  3305.  * As a shorthand, the desired HTTP response code may be passed as an integer to
  3306.  * the `$title` parameter (the default title would apply) or the `$args` parameter.
  3307.  *
  3308.  * @since 2.0.4
  3309.  * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
  3310.  *              an integer to be used as the response code.
  3311.  * @since 5.1.0 The `$link_url`, `$link_text`, and `$exit` arguments were added.
  3312.  * @since 5.3.0 The `$charset` argument was added.
  3313.  * @since 5.5.0 The `$text_direction` argument has a priority over get_language_attributes()
  3314.  *              in the default handler.
  3315.  *
  3316.  * @global WP_Query $wp_query WordPress Query object.
  3317.  *
  3318.  * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
  3319.  *                                  and not an Ajax or XML-RPC request, the error's messages are used.
  3320.  *                                  Default empty string.
  3321.  * @param string|int       $title   Optional. Error title. If `$message` is a `WP_Error` object,
  3322.  *                                  error data with the key 'title' may be used to specify the title.
  3323.  *                                  If `$title` is an integer, then it is treated as the response code.
  3324.  *                                  Default empty string.
  3325.  * @param string|array|int $args {
  3326.  *     Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
  3327.  *     as the response code. Default empty array.
  3328.  *
  3329.  *     @type int    $response       The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
  3330.  *     @type string $link_url       A URL to include a link to. Only works in combination with $link_text.
  3331.  *                                  Default empty string.
  3332.  *     @type string $link_text      A label for the link to include. Only works in combination with $link_url.
  3333.  *                                  Default empty string.
  3334.  *     @type bool   $back_link      Whether to include a link to go back. Default false.
  3335.  *     @type string $text_direction The text direction. This is only useful internally, when WordPress is still
  3336.  *                                  loading and the site's locale is not set up yet. Accepts 'rtl' and 'ltr'.
  3337.  *                                  Default is the value of is_rtl().
  3338.  *     @type string $charset        Character set of the HTML output. Default 'utf-8'.
  3339.  *     @type string $code           Error code to use. Default is 'wp_die', or the main error code if $message
  3340.  *                                  is a WP_Error.
  3341.  *     @type bool   $exit           Whether to exit the process after completion. Default true.
  3342.  * }
  3343.  */
  3344. function wp_die$message ''$title ''$args = array() ) {
  3345.     global $wp_query;
  3346.     if ( is_int$args ) ) {
  3347.         $args = array( 'response' => $args );
  3348.     } elseif ( is_int$title ) ) {
  3349.         $args  = array( 'response' => $title );
  3350.         $title '';
  3351.     }
  3352.     if ( wp_doing_ajax() ) {
  3353.         /**
  3354.          * Filters the callback for killing WordPress execution for Ajax requests.
  3355.          *
  3356.          * @since 3.4.0
  3357.          *
  3358.          * @param callable $callback Callback function name.
  3359.          */
  3360.         $callback apply_filters'wp_die_ajax_handler''_ajax_wp_die_handler' );
  3361.     } elseif ( wp_is_json_request() ) {
  3362.         /**
  3363.          * Filters the callback for killing WordPress execution for JSON requests.
  3364.          *
  3365.          * @since 5.1.0
  3366.          *
  3367.          * @param callable $callback Callback function name.
  3368.          */
  3369.         $callback apply_filters'wp_die_json_handler''_json_wp_die_handler' );
  3370.     } elseif ( wp_is_serving_rest_request() && wp_is_jsonp_request() ) {
  3371.         /**
  3372.          * Filters the callback for killing WordPress execution for JSONP REST requests.
  3373.          *
  3374.          * @since 5.2.0
  3375.          *
  3376.          * @param callable $callback Callback function name.
  3377.          */
  3378.         $callback apply_filters'wp_die_jsonp_handler''_jsonp_wp_die_handler' );
  3379.     } elseif ( defined'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
  3380.         /**
  3381.          * Filters the callback for killing WordPress execution for XML-RPC requests.
  3382.          *
  3383.          * @since 3.4.0
  3384.          *
  3385.          * @param callable $callback Callback function name.
  3386.          */
  3387.         $callback apply_filters'wp_die_xmlrpc_handler''_xmlrpc_wp_die_handler' );
  3388.     } elseif ( wp_is_xml_request()
  3389.         || isset( $wp_query ) &&
  3390.             ( function_exists'is_feed' ) && is_feed()
  3391.             || function_exists'is_comment_feed' ) && is_comment_feed()
  3392.             || function_exists'is_trackback' ) && is_trackback() ) ) {
  3393.         /**
  3394.          * Filters the callback for killing WordPress execution for XML requests.
  3395.          *
  3396.          * @since 5.2.0
  3397.          *
  3398.          * @param callable $callback Callback function name.
  3399.          */
  3400.         $callback apply_filters'wp_die_xml_handler''_xml_wp_die_handler' );
  3401.     } else {
  3402.         /**
  3403.          * Filters the callback for killing WordPress execution for all non-Ajax, non-JSON, non-XML requests.
  3404.          *
  3405.          * @since 3.0.0
  3406.          *
  3407.          * @param callable $callback Callback function name.
  3408.          */
  3409.         $callback apply_filters'wp_die_handler''_default_wp_die_handler' );
  3410.     }
  3411.     call_user_func$callback$message$title$args );
  3412. }
  3413. /**
  3414.  * Kills WordPress execution and displays HTML page with an error message.
  3415.  *
  3416.  * This is the default handler for wp_die(). If you want a custom one,
  3417.  * you can override this using the {@see 'wp_die_handler'} filter in wp_die().
  3418.  *
  3419.  * @since 3.0.0
  3420.  * @access private
  3421.  *
  3422.  * @param string|WP_Error $message Error message or WP_Error object.
  3423.  * @param string          $title   Optional. Error title. Default empty string.
  3424.  * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
  3425.  */
  3426. function _default_wp_die_handler$message$title ''$args = array() ) {
  3427.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3428.     if ( is_string$message ) ) {
  3429.         if ( ! empty( $parsed_args['additional_errors'] ) ) {
  3430.             $message array_merge(
  3431.                 array( $message ),
  3432.                 wp_list_pluck$parsed_args['additional_errors'], 'message' )
  3433.             );
  3434.             $message "<ul>\n\t\t<li>" implode"</li>\n\t\t<li>"$message ) . "</li>\n\t</ul>";
  3435.         }
  3436.         $message sprintf(
  3437.             '<div class="wp-die-message">%s</div>',
  3438.             $message
  3439.         );
  3440.     }
  3441.     $have_gettext function_exists'__' );
  3442.     if ( ! empty( $parsed_args['link_url'] ) && ! empty( $parsed_args['link_text'] ) ) {
  3443.         $link_url $parsed_args['link_url'];
  3444.         if ( function_exists'esc_url' ) ) {
  3445.             $link_url esc_url$link_url );
  3446.         }
  3447.         $link_text $parsed_args['link_text'];
  3448.         $message  .= "\n<p><a href='{$link_url}'>{$link_text}</a></p>";
  3449.     }
  3450.     if ( isset( $parsed_args['back_link'] ) && $parsed_args['back_link'] ) {
  3451.         $back_text $have_gettext __'&laquo; Back' ) : '&laquo; Back';
  3452.         $message  .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
  3453.     }
  3454.     if ( ! did_action'admin_head' ) ) :
  3455.         if ( ! headers_sent() ) {
  3456.             header"Content-Type: text/html; charset={$parsed_args['charset']});
  3457.             status_header$parsed_args['response'] );
  3458.             nocache_headers();
  3459.         }
  3460.         $text_direction $parsed_args['text_direction'];
  3461.         $dir_attr       "dir='$text_direction'";
  3462.         /*
  3463.          * If `text_direction` was not explicitly passed,
  3464.          * use get_language_attributes() if available.
  3465.          */
  3466.         if ( empty( $args['text_direction'] )
  3467.             && function_exists'language_attributes' ) && function_exists'is_rtl' )
  3468.         ) {
  3469.             $dir_attr get_language_attributes();
  3470.         }
  3471.         ?>
  3472. <!DOCTYPE html>
  3473. <html <?php echo $dir_attr?>>
  3474. <head>
  3475.     <meta http-equiv="Content-Type" content="text/html; charset=<?php echo $parsed_args['charset']; ?>" />
  3476.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  3477.         <?php
  3478.         if ( function_exists'wp_robots' ) && function_exists'wp_robots_no_robots' ) && function_exists'add_filter' ) ) {
  3479.             add_filter'wp_robots''wp_robots_no_robots' );
  3480.             // Prevent warnings because of $wp_query not existing.
  3481.             remove_filter'wp_robots''wp_robots_noindex_embeds' );
  3482.             remove_filter'wp_robots''wp_robots_noindex_search' );
  3483.             wp_robots();
  3484.         }
  3485.         ?>
  3486.     <title><?php echo $title?></title>
  3487.     <style type="text/css">
  3488.         html {
  3489.             background: #f1f1f1;
  3490.         }
  3491.         body {
  3492.             background: #fff;
  3493.             border: 1px solid #ccd0d4;
  3494.             color: #444;
  3495.             font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  3496.             margin: 2em auto;
  3497.             padding: 1em 2em;
  3498.             max-width: 700px;
  3499.             -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
  3500.             box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
  3501.         }
  3502.         h1 {
  3503.             border-bottom: 1px solid #dadada;
  3504.             clear: both;
  3505.             color: #666;
  3506.             font-size: 24px;
  3507.             margin: 30px 0 0 0;
  3508.             padding: 0;
  3509.             padding-bottom: 7px;
  3510.         }
  3511.         #error-page {
  3512.             margin-top: 50px;
  3513.         }
  3514.         #error-page p,
  3515.         #error-page .wp-die-message {
  3516.             font-size: 14px;
  3517.             line-height: 1.5;
  3518.             margin: 25px 0 20px;
  3519.         }
  3520.         #error-page code {
  3521.             font-family: Consolas, Monaco, monospace;
  3522.         }
  3523.         ul li {
  3524.             margin-bottom: 10px;
  3525.             font-size: 14px ;
  3526.         }
  3527.         a {
  3528.             color: #2271b1;
  3529.         }
  3530.         a:hover,
  3531.         a:active {
  3532.             color: #135e96;
  3533.         }
  3534.         a:focus {
  3535.             color: #043959;
  3536.             box-shadow: 0 0 0 2px #2271b1;
  3537.             outline: 2px solid transparent;
  3538.         }
  3539.         .button {
  3540.             background: #f3f5f6;
  3541.             border: 1px solid #016087;
  3542.             color: #016087;
  3543.             display: inline-block;
  3544.             text-decoration: none;
  3545.             font-size: 13px;
  3546.             line-height: 2;
  3547.             height: 28px;
  3548.             margin: 0;
  3549.             padding: 0 10px 1px;
  3550.             cursor: pointer;
  3551.             -webkit-border-radius: 3px;
  3552.             -webkit-appearance: none;
  3553.             border-radius: 3px;
  3554.             white-space: nowrap;
  3555.             -webkit-box-sizing: border-box;
  3556.             -moz-box-sizing:    border-box;
  3557.             box-sizing:         border-box;
  3558.             vertical-align: top;
  3559.         }
  3560.         .button.button-large {
  3561.             line-height: 2.30769231;
  3562.             min-height: 32px;
  3563.             padding: 0 12px;
  3564.         }
  3565.         .button:hover,
  3566.         .button:focus {
  3567.             background: #f1f1f1;
  3568.         }
  3569.         .button:focus {
  3570.             background: #f3f5f6;
  3571.             border-color: #007cba;
  3572.             -webkit-box-shadow: 0 0 0 1px #007cba;
  3573.             box-shadow: 0 0 0 1px #007cba;
  3574.             color: #016087;
  3575.             outline: 2px solid transparent;
  3576.             outline-offset: 0;
  3577.         }
  3578.         .button:active {
  3579.             background: #f3f5f6;
  3580.             border-color: #7e8993;
  3581.             -webkit-box-shadow: none;
  3582.             box-shadow: none;
  3583.         }
  3584.         <?php
  3585.         if ( 'rtl' === $text_direction ) {
  3586.             echo 'body { font-family: Tahoma, Arial; }';
  3587.         }
  3588.         ?>
  3589.     </style>
  3590. </head>
  3591. <body id="error-page">
  3592. <?php endif; // ! did_action( 'admin_head' ) ?>
  3593.     <?php echo $message?>
  3594. </body>
  3595. </html>
  3596.     <?php
  3597.     if ( $parsed_args['exit'] ) {
  3598.         die();
  3599.     }
  3600. }
  3601. /**
  3602.  * Kills WordPress execution and displays Ajax response with an error message.
  3603.  *
  3604.  * This is the handler for wp_die() when processing Ajax requests.
  3605.  *
  3606.  * @since 3.4.0
  3607.  * @access private
  3608.  *
  3609.  * @param string       $message Error message.
  3610.  * @param string       $title   Optional. Error title (unused). Default empty string.
  3611.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3612.  */
  3613. function _ajax_wp_die_handler$message$title ''$args = array() ) {
  3614.     // Set default 'response' to 200 for Ajax requests.
  3615.     $args wp_parse_args(
  3616.         $args,
  3617.         array( 'response' => 200 )
  3618.     );
  3619.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3620.     if ( ! headers_sent() ) {
  3621.         // This is intentional. For backward-compatibility, support passing null here.
  3622.         if ( null !== $args['response'] ) {
  3623.             status_header$parsed_args['response'] );
  3624.         }
  3625.         nocache_headers();
  3626.     }
  3627.     if ( is_scalar$message ) ) {
  3628.         $message = (string) $message;
  3629.     } else {
  3630.         $message '0';
  3631.     }
  3632.     if ( $parsed_args['exit'] ) {
  3633.         die( $message );
  3634.     }
  3635.     echo $message;
  3636. }
  3637. /**
  3638.  * Kills WordPress execution and displays JSON response with an error message.
  3639.  *
  3640.  * This is the handler for wp_die() when processing JSON requests.
  3641.  *
  3642.  * @since 5.1.0
  3643.  * @access private
  3644.  *
  3645.  * @param string       $message Error message.
  3646.  * @param string       $title   Optional. Error title. Default empty string.
  3647.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3648.  */
  3649. function _json_wp_die_handler$message$title ''$args = array() ) {
  3650.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3651.     $data = array(
  3652.         'code'              => $parsed_args['code'],
  3653.         'message'           => $message,
  3654.         'data'              => array(
  3655.             'status' => $parsed_args['response'],
  3656.         ),
  3657.         'additional_errors' => $parsed_args['additional_errors'],
  3658.     );
  3659.     if ( isset( $parsed_args['error_data'] ) ) {
  3660.         $data['data']['error'] = $parsed_args['error_data'];
  3661.     }
  3662.     if ( ! headers_sent() ) {
  3663.         header"Content-Type: application/json; charset={$parsed_args['charset']});
  3664.         if ( null !== $parsed_args['response'] ) {
  3665.             status_header$parsed_args['response'] );
  3666.         }
  3667.         nocache_headers();
  3668.     }
  3669.     echo wp_json_encode$data );
  3670.     if ( $parsed_args['exit'] ) {
  3671.         die();
  3672.     }
  3673. }
  3674. /**
  3675.  * Kills WordPress execution and displays JSONP response with an error message.
  3676.  *
  3677.  * This is the handler for wp_die() when processing JSONP requests.
  3678.  *
  3679.  * @since 5.2.0
  3680.  * @access private
  3681.  *
  3682.  * @param string       $message Error message.
  3683.  * @param string       $title   Optional. Error title. Default empty string.
  3684.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3685.  */
  3686. function _jsonp_wp_die_handler$message$title ''$args = array() ) {
  3687.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3688.     $data = array(
  3689.         'code'              => $parsed_args['code'],
  3690.         'message'           => $message,
  3691.         'data'              => array(
  3692.             'status' => $parsed_args['response'],
  3693.         ),
  3694.         'additional_errors' => $parsed_args['additional_errors'],
  3695.     );
  3696.     if ( isset( $parsed_args['error_data'] ) ) {
  3697.         $data['data']['error'] = $parsed_args['error_data'];
  3698.     }
  3699.     if ( ! headers_sent() ) {
  3700.         header"Content-Type: application/javascript; charset={$parsed_args['charset']});
  3701.         header'X-Content-Type-Options: nosniff' );
  3702.         header'X-Robots-Tag: noindex' );
  3703.         if ( null !== $parsed_args['response'] ) {
  3704.             status_header$parsed_args['response'] );
  3705.         }
  3706.         nocache_headers();
  3707.     }
  3708.     $result         wp_json_encode$data );
  3709.     $jsonp_callback $_GET['_jsonp'];
  3710.     echo '/**/' $jsonp_callback '(' $result ')';
  3711.     if ( $parsed_args['exit'] ) {
  3712.         die();
  3713.     }
  3714. }
  3715. /**
  3716.  * Kills WordPress execution and displays XML response with an error message.
  3717.  *
  3718.  * This is the handler for wp_die() when processing XMLRPC requests.
  3719.  *
  3720.  * @since 3.2.0
  3721.  * @access private
  3722.  *
  3723.  * @global wp_xmlrpc_server $wp_xmlrpc_server
  3724.  *
  3725.  * @param string       $message Error message.
  3726.  * @param string       $title   Optional. Error title. Default empty string.
  3727.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3728.  */
  3729. function _xmlrpc_wp_die_handler$message$title ''$args = array() ) {
  3730.     global $wp_xmlrpc_server;
  3731.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3732.     if ( ! headers_sent() ) {
  3733.         nocache_headers();
  3734.     }
  3735.     if ( $wp_xmlrpc_server ) {
  3736.         $error = new IXR_Error$parsed_args['response'], $message );
  3737.         $wp_xmlrpc_server->output$error->getXml() );
  3738.     }
  3739.     if ( $parsed_args['exit'] ) {
  3740.         die();
  3741.     }
  3742. }
  3743. /**
  3744.  * Kills WordPress execution and displays XML response with an error message.
  3745.  *
  3746.  * This is the handler for wp_die() when processing XML requests.
  3747.  *
  3748.  * @since 5.2.0
  3749.  * @access private
  3750.  *
  3751.  * @param string       $message Error message.
  3752.  * @param string       $title   Optional. Error title. Default empty string.
  3753.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3754.  */
  3755. function _xml_wp_die_handler$message$title ''$args = array() ) {
  3756.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3757.     $message htmlspecialchars$message );
  3758.     $title   htmlspecialchars$title );
  3759.     $xml = <<<EOD
  3760. <error>
  3761.     <code>{$parsed_args['code']}</code>
  3762.     <title><![CDATA[{$title}]]></title>
  3763.     <message><![CDATA[{$message}]]></message>
  3764.     <data>
  3765.         <status>{$parsed_args['response']}</status>
  3766.     </data>
  3767. </error>
  3768. EOD;
  3769.     if ( ! headers_sent() ) {
  3770.         header"Content-Type: text/xml; charset={$parsed_args['charset']});
  3771.         if ( null !== $parsed_args['response'] ) {
  3772.             status_header$parsed_args['response'] );
  3773.         }
  3774.         nocache_headers();
  3775.     }
  3776.     echo $xml;
  3777.     if ( $parsed_args['exit'] ) {
  3778.         die();
  3779.     }
  3780. }
  3781. /**
  3782.  * Kills WordPress execution and displays an error message.
  3783.  *
  3784.  * This is the handler for wp_die() when processing APP requests.
  3785.  *
  3786.  * @since 3.4.0
  3787.  * @since 5.1.0 Added the $title and $args parameters.
  3788.  * @access private
  3789.  *
  3790.  * @param string       $message Optional. Response to print. Default empty string.
  3791.  * @param string       $title   Optional. Error title (unused). Default empty string.
  3792.  * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
  3793.  */
  3794. function _scalar_wp_die_handler$message ''$title ''$args = array() ) {
  3795.     list( $message$title$parsed_args ) = _wp_die_process_input$message$title$args );
  3796.     if ( $parsed_args['exit'] ) {
  3797.         if ( is_scalar$message ) ) {
  3798.             die( (string) $message );
  3799.         }
  3800.         die();
  3801.     }
  3802.     if ( is_scalar$message ) ) {
  3803.         echo (string) $message;
  3804.     }
  3805. }
  3806. /**
  3807.  * Processes arguments passed to wp_die() consistently for its handlers.
  3808.  *
  3809.  * @since 5.1.0
  3810.  * @access private
  3811.  *
  3812.  * @param string|WP_Error $message Error message or WP_Error object.
  3813.  * @param string          $title   Optional. Error title. Default empty string.
  3814.  * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
  3815.  * @return array {
  3816.  *     Processed arguments.
  3817.  *
  3818.  *     @type string $0 Error message.
  3819.  *     @type string $1 Error title.
  3820.  *     @type array  $2 Arguments to control behavior.
  3821.  * }
  3822.  */
  3823. function _wp_die_process_input$message$title ''$args = array() ) {
  3824.     $defaults = array(
  3825.         'response'          => 0,
  3826.         'code'              => '',
  3827.         'exit'              => true,
  3828.         'back_link'         => false,
  3829.         'link_url'          => '',
  3830.         'link_text'         => '',
  3831.         'text_direction'    => '',
  3832.         'charset'           => 'utf-8',
  3833.         'additional_errors' => array(),
  3834.     );
  3835.     $args wp_parse_args$args$defaults );
  3836.     if ( function_exists'is_wp_error' ) && is_wp_error$message ) ) {
  3837.         if ( ! empty( $message->errors ) ) {
  3838.             $errors = array();
  3839.             foreach ( (array) $message->errors as $error_code => $error_messages ) {
  3840.                 foreach ( (array) $error_messages as $error_message ) {
  3841.                     $errors[] = array(
  3842.                         'code'    => $error_code,
  3843.                         'message' => $error_message,
  3844.                         'data'    => $message->get_error_data$error_code ),
  3845.                     );
  3846.                 }
  3847.             }
  3848.             $message $errors[0]['message'];
  3849.             if ( empty( $args['code'] ) ) {
  3850.                 $args['code'] = $errors[0]['code'];
  3851.             }
  3852.             if ( empty( $args['response'] ) && is_array$errors[0]['data'] ) && ! empty( $errors[0]['data']['status'] ) ) {
  3853.                 $args['response'] = $errors[0]['data']['status'];
  3854.             }
  3855.             if ( empty( $title ) && is_array$errors[0]['data'] ) && ! empty( $errors[0]['data']['title'] ) ) {
  3856.                 $title $errors[0]['data']['title'];
  3857.             }
  3858.             if ( WP_DEBUG_DISPLAY && is_array$errors[0]['data'] ) && ! empty( $errors[0]['data']['error'] ) ) {
  3859.                 $args['error_data'] = $errors[0]['data']['error'];
  3860.             }
  3861.             unset( $errors[0] );
  3862.             $args['additional_errors'] = array_values$errors );
  3863.         } else {
  3864.             $message '';
  3865.         }
  3866.     }
  3867.     $have_gettext function_exists'__' );
  3868.     // The $title and these specific $args must always have a non-empty value.
  3869.     if ( empty( $args['code'] ) ) {
  3870.         $args['code'] = 'wp_die';
  3871.     }
  3872.     if ( empty( $args['response'] ) ) {
  3873.         $args['response'] = 500;
  3874.     }
  3875.     if ( empty( $title ) ) {
  3876.         $title $have_gettext __'WordPress &rsaquo; Error' ) : 'WordPress &rsaquo; Error';
  3877.     }
  3878.     if ( empty( $args['text_direction'] ) || ! in_array$args['text_direction'], array( 'ltr''rtl' ), true ) ) {
  3879.         $args['text_direction'] = 'ltr';
  3880.         if ( function_exists'is_rtl' ) && is_rtl() ) {
  3881.             $args['text_direction'] = 'rtl';
  3882.         }
  3883.     }
  3884.     if ( ! empty( $args['charset'] ) ) {
  3885.         $args['charset'] = _canonical_charset$args['charset'] );
  3886.     }
  3887.     return array( $message$title$args );
  3888. }
  3889. /**
  3890.  * Encodes a variable into JSON, with some confidence checks.
  3891.  *
  3892.  * @since 4.1.0
  3893.  * @since 5.3.0 No longer handles support for PHP < 5.6.
  3894.  * @since 6.5.0 The `$data` parameter has been renamed to `$value` and
  3895.  *              the `$options` parameter to `$flags` for parity with PHP.
  3896.  *
  3897.  * @param mixed $value Variable (usually an array or object) to encode as JSON.
  3898.  * @param int   $flags Optional. Options to be passed to json_encode(). Default 0.
  3899.  * @param int   $depth Optional. Maximum depth to walk through $value. Must be
  3900.  *                     greater than 0. Default 512.
  3901.  * @return string|false The JSON encoded string, or false if it cannot be encoded.
  3902.  */
  3903. function wp_json_encode$value$flags 0$depth 512 ) {
  3904.     $json json_encode$value$flags$depth );
  3905.     // If json_encode() was successful, no need to do more confidence checking.
  3906.     if ( false !== $json ) {
  3907.         return $json;
  3908.     }
  3909.     try {
  3910.         $value _wp_json_sanity_check$value$depth );
  3911.     } catch ( Exception $e ) {
  3912.         return false;
  3913.     }
  3914.     return json_encode$value$flags$depth );
  3915. }
  3916. /**
  3917.  * Performs confidence checks on data that shall be encoded to JSON.
  3918.  *
  3919.  * @ignore
  3920.  * @since 4.1.0
  3921.  * @access private
  3922.  *
  3923.  * @see wp_json_encode()
  3924.  *
  3925.  * @throws Exception If depth limit is reached.
  3926.  *
  3927.  * @param mixed $value Variable (usually an array or object) to encode as JSON.
  3928.  * @param int   $depth Maximum depth to walk through $value. Must be greater than 0.
  3929.  * @return mixed The sanitized data that shall be encoded to JSON.
  3930.  */
  3931. function _wp_json_sanity_check$value$depth ) {
  3932.     if ( $depth ) {
  3933.         throw new Exception'Reached depth limit' );
  3934.     }
  3935.     if ( is_array$value ) ) {
  3936.         $output = array();
  3937.         foreach ( $value as $id => $el ) {
  3938.             // Don't forget to sanitize the ID!
  3939.             if ( is_string$id ) ) {
  3940.                 $clean_id _wp_json_convert_string$id );
  3941.             } else {
  3942.                 $clean_id $id;
  3943.             }
  3944.             // Check the element type, so that we're only recursing if we really have to.
  3945.             if ( is_array$el ) || is_object$el ) ) {
  3946.                 $output$clean_id ] = _wp_json_sanity_check$el$depth );
  3947.             } elseif ( is_string$el ) ) {
  3948.                 $output$clean_id ] = _wp_json_convert_string$el );
  3949.             } else {
  3950.                 $output$clean_id ] = $el;
  3951.             }
  3952.         }
  3953.     } elseif ( is_object$value ) ) {
  3954.         $output = new stdClass();
  3955.         foreach ( $value as $id => $el ) {
  3956.             if ( is_string$id ) ) {
  3957.                 $clean_id _wp_json_convert_string$id );
  3958.             } else {
  3959.                 $clean_id $id;
  3960.             }
  3961.             if ( is_array$el ) || is_object$el ) ) {
  3962.                 $output->$clean_id _wp_json_sanity_check$el$depth );
  3963.             } elseif ( is_string$el ) ) {
  3964.                 $output->$clean_id _wp_json_convert_string$el );
  3965.             } else {
  3966.                 $output->$clean_id $el;
  3967.             }
  3968.         }
  3969.     } elseif ( is_string$value ) ) {
  3970.         return _wp_json_convert_string$value );
  3971.     } else {
  3972.         return $value;
  3973.     }
  3974.     return $output;
  3975. }
  3976. /**
  3977.  * Converts a string to UTF-8, so that it can be safely encoded to JSON.
  3978.  *
  3979.  * @ignore
  3980.  * @since 4.1.0
  3981.  * @access private
  3982.  *
  3983.  * @see _wp_json_sanity_check()
  3984.  *
  3985.  * @param string $input_string The string which is to be converted.
  3986.  * @return string The checked string.
  3987.  */
  3988. function _wp_json_convert_string$input_string ) {
  3989.     static $use_mb null;
  3990.     if ( is_null$use_mb ) ) {
  3991.         $use_mb function_exists'mb_convert_encoding' );
  3992.     }
  3993.     if ( $use_mb ) {
  3994.         $encoding mb_detect_encoding$input_stringmb_detect_order(), true );
  3995.         if ( $encoding ) {
  3996.             return mb_convert_encoding$input_string'UTF-8'$encoding );
  3997.         } else {
  3998.             return mb_convert_encoding$input_string'UTF-8''UTF-8' );
  3999.         }
  4000.     } else {
  4001.         return wp_check_invalid_utf8$input_stringtrue );
  4002.     }
  4003. }
  4004. /**
  4005.  * Prepares response data to be serialized to JSON.
  4006.  *
  4007.  * This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
  4008.  *
  4009.  * @ignore
  4010.  * @since 4.4.0
  4011.  * @deprecated 5.3.0 This function is no longer needed as support for PHP 5.2-5.3
  4012.  *                   has been dropped.
  4013.  * @access private
  4014.  *
  4015.  * @param mixed $value Native representation.
  4016.  * @return bool|int|float|null|string|array Data ready for `json_encode()`.
  4017.  */
  4018. function _wp_json_prepare_data$value ) {
  4019.     _deprecated_function__FUNCTION__'5.3.0' );
  4020.     return $value;
  4021. }
  4022. /**
  4023.  * Sends a JSON response back to an Ajax request.
  4024.  *
  4025.  * @since 3.5.0
  4026.  * @since 4.7.0 The `$status_code` parameter was added.
  4027.  * @since 5.6.0 The `$flags` parameter was added.
  4028.  *
  4029.  * @param mixed $response    Variable (usually an array or object) to encode as JSON,
  4030.  *                           then print and die.
  4031.  * @param int   $status_code Optional. The HTTP status code to output. Default null.
  4032.  * @param int   $flags       Optional. Options to be passed to json_encode(). Default 0.
  4033.  */
  4034. function wp_send_json$response$status_code null$flags ) {
  4035.     if ( wp_is_serving_rest_request() ) {
  4036.         _doing_it_wrong(
  4037.             __FUNCTION__,
  4038.             sprintf(
  4039.                 /* translators: 1: WP_REST_Response, 2: WP_Error */
  4040.                 __'Return a %1$s or %2$s object from your callback when using the REST API.' ),
  4041.                 'WP_REST_Response',
  4042.                 'WP_Error'
  4043.             ),
  4044.             '5.5.0'
  4045.         );
  4046.     }
  4047.     if ( ! headers_sent() ) {
  4048.         header'Content-Type: application/json; charset=' get_option'blog_charset' ) );
  4049.         if ( null !== $status_code ) {
  4050.             status_header$status_code );
  4051.         }
  4052.     }
  4053.     echo wp_json_encode$response$flags );
  4054.     if ( wp_doing_ajax() ) {
  4055.         wp_die(
  4056.             '',
  4057.             '',
  4058.             array(
  4059.                 'response' => null,
  4060.             )
  4061.         );
  4062.     } else {
  4063.         die;
  4064.     }
  4065. }
  4066. /**
  4067.  * Sends a JSON response back to an Ajax request, indicating success.
  4068.  *
  4069.  * @since 3.5.0
  4070.  * @since 4.7.0 The `$status_code` parameter was added.
  4071.  * @since 5.6.0 The `$flags` parameter was added.
  4072.  *
  4073.  * @param mixed $value       Optional. Data to encode as JSON, then print and die. Default null.
  4074.  * @param int   $status_code Optional. The HTTP status code to output. Default null.
  4075.  * @param int   $flags       Optional. Options to be passed to json_encode(). Default 0.
  4076.  */
  4077. function wp_send_json_success$value null$status_code null$flags ) {
  4078.     $response = array( 'success' => true );
  4079.     if ( isset( $value ) ) {
  4080.         $response['data'] = $value;
  4081.     }
  4082.     wp_send_json$response$status_code$flags );
  4083. }
  4084. /**
  4085.  * Sends a JSON response back to an Ajax request, indicating failure.
  4086.  *
  4087.  * If the `$value` parameter is a WP_Error object, the errors
  4088.  * within the object are processed and output as an array of error
  4089.  * codes and corresponding messages. All other types are output
  4090.  * without further processing.
  4091.  *
  4092.  * @since 3.5.0
  4093.  * @since 4.1.0 The `$value` parameter is now processed if a WP_Error object is passed in.
  4094.  * @since 4.7.0 The `$status_code` parameter was added.
  4095.  * @since 5.6.0 The `$flags` parameter was added.
  4096.  *
  4097.  * @param mixed $value       Optional. Data to encode as JSON, then print and die. Default null.
  4098.  * @param int   $status_code Optional. The HTTP status code to output. Default null.
  4099.  * @param int   $flags       Optional. Options to be passed to json_encode(). Default 0.
  4100.  */
  4101. function wp_send_json_error$value null$status_code null$flags ) {
  4102.     $response = array( 'success' => false );
  4103.     if ( isset( $value ) ) {
  4104.         if ( is_wp_error$value ) ) {
  4105.             $result = array();
  4106.             foreach ( $value->errors as $code => $messages ) {
  4107.                 foreach ( $messages as $message ) {
  4108.                     $result[] = array(
  4109.                         'code'    => $code,
  4110.                         'message' => $message,
  4111.                     );
  4112.                 }
  4113.             }
  4114.             $response['data'] = $result;
  4115.         } else {
  4116.             $response['data'] = $value;
  4117.         }
  4118.     }
  4119.     wp_send_json$response$status_code$flags );
  4120. }
  4121. /**
  4122.  * Checks that a JSONP callback is a valid JavaScript callback name.
  4123.  *
  4124.  * Only allows alphanumeric characters and the dot character in callback
  4125.  * function names. This helps to mitigate XSS attacks caused by directly
  4126.  * outputting user input.
  4127.  *
  4128.  * @since 4.6.0
  4129.  *
  4130.  * @param string $callback Supplied JSONP callback function name.
  4131.  * @return bool Whether the callback function name is valid.
  4132.  */
  4133. function wp_check_jsonp_callback$callback ) {
  4134.     if ( ! is_string$callback ) ) {
  4135.         return false;
  4136.     }
  4137.     preg_replace'/[^\w\.]/'''$callback, -1$illegal_char_count );
  4138.     return === $illegal_char_count;
  4139. }
  4140. /**
  4141.  * Reads and decodes a JSON file.
  4142.  *
  4143.  * @since 5.9.0
  4144.  *
  4145.  * @param string $filename Path to the JSON file.
  4146.  * @param array  $options  {
  4147.  *     Optional. Options to be used with `json_decode()`.
  4148.  *
  4149.  *     @type bool $associative Optional. When `true`, JSON objects will be returned as associative arrays.
  4150.  *                             When `false`, JSON objects will be returned as objects. Default false.
  4151.  * }
  4152.  *
  4153.  * @return mixed Returns the value encoded in JSON in appropriate PHP type.
  4154.  *               `null` is returned if the file is not found, or its content can't be decoded.
  4155.  */
  4156. function wp_json_file_decode$filename$options = array() ) {
  4157.     $result   null;
  4158.     $filename wp_normalize_pathrealpath$filename ) );
  4159.     if ( ! $filename ) {
  4160.         wp_trigger_error(
  4161.             __FUNCTION__,
  4162.             sprintf(
  4163.                 /* translators: %s: Path to the JSON file. */
  4164.                 __"File %s doesn't exist!" ),
  4165.                 $filename
  4166.             )
  4167.         );
  4168.         return $result;
  4169.     }
  4170.     $options      wp_parse_args$options, array( 'associative' => false ) );
  4171.     $decoded_file json_decodefile_get_contents$filename ), $options['associative'] );
  4172.     if ( JSON_ERROR_NONE !== json_last_error() ) {
  4173.         wp_trigger_error(
  4174.             __FUNCTION__,
  4175.             sprintf(
  4176.                 /* translators: 1: Path to the JSON file, 2: Error message. */
  4177.                 __'Error when decoding a JSON file at path %1$s: %2$s' ),
  4178.                 $filename,
  4179.                 json_last_error_msg()
  4180.             )
  4181.         );
  4182.         return $result;
  4183.     }
  4184.     return $decoded_file;
  4185. }
  4186. /**
  4187.  * Retrieves the WordPress home page URL.
  4188.  *
  4189.  * If the constant named 'WP_HOME' exists, then it will be used and returned
  4190.  * by the function. This can be used to counter the redirection on your local
  4191.  * development environment.
  4192.  *
  4193.  * @since 2.2.0
  4194.  * @access private
  4195.  *
  4196.  * @see WP_HOME
  4197.  *
  4198.  * @param string $url URL for the home location.
  4199.  * @return string Homepage location.
  4200.  */
  4201. function _config_wp_home$url '' ) {
  4202.     if ( defined'WP_HOME' ) ) {
  4203.         return untrailingslashitWP_HOME );
  4204.     }
  4205.     return $url;
  4206. }
  4207. /**
  4208.  * Retrieves the WordPress site URL.
  4209.  *
  4210.  * If the constant named 'WP_SITEURL' is defined, then the value in that
  4211.  * constant will always be returned. This can be used for debugging a site
  4212.  * on your localhost while not having to change the database to your URL.
  4213.  *
  4214.  * @since 2.2.0
  4215.  * @access private
  4216.  *
  4217.  * @see WP_SITEURL
  4218.  *
  4219.  * @param string $url URL to set the WordPress site location.
  4220.  * @return string The WordPress site URL.
  4221.  */
  4222. function _config_wp_siteurl$url '' ) {
  4223.     if ( defined'WP_SITEURL' ) ) {
  4224.         return untrailingslashitWP_SITEURL );
  4225.     }
  4226.     return $url;
  4227. }
  4228. /**
  4229.  * Deletes the fresh site option.
  4230.  *
  4231.  * @since 4.7.0
  4232.  * @access private
  4233.  */
  4234. function _delete_option_fresh_site() {
  4235.     update_option'fresh_site''0'false );
  4236. }
  4237. /**
  4238.  * Sets the localized direction for MCE plugin.
  4239.  *
  4240.  * Will only set the direction to 'rtl', if the WordPress locale has
  4241.  * the text direction set to 'rtl'.
  4242.  *
  4243.  * Fills in the 'directionality' setting, enables the 'directionality'
  4244.  * plugin, and adds the 'ltr' button to 'toolbar1', formerly
  4245.  * 'theme_advanced_buttons1' array keys. These keys are then returned
  4246.  * in the $mce_init (TinyMCE settings) array.
  4247.  *
  4248.  * @since 2.1.0
  4249.  * @access private
  4250.  *
  4251.  * @param array $mce_init MCE settings array.
  4252.  * @return array Direction set for 'rtl', if needed by locale.
  4253.  */
  4254. function _mce_set_direction$mce_init ) {
  4255.     if ( is_rtl() ) {
  4256.         $mce_init['directionality'] = 'rtl';
  4257.         $mce_init['rtl_ui']         = true;
  4258.         if ( ! empty( $mce_init['plugins'] ) && ! str_contains$mce_init['plugins'], 'directionality' ) ) {
  4259.             $mce_init['plugins'] .= ',directionality';
  4260.         }
  4261.         if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match'/\bltr\b/'$mce_init['toolbar1'] ) ) {
  4262.             $mce_init['toolbar1'] .= ',ltr';
  4263.         }
  4264.     }
  4265.     return $mce_init;
  4266. }
  4267. /**
  4268.  * Determines whether WordPress is currently serving a REST API request.
  4269.  *
  4270.  * The function relies on the 'REST_REQUEST' global. As such, it only returns true when an actual REST _request_ is
  4271.  * being made. It does not return true when a REST endpoint is hit as part of another request, e.g. for preloading a
  4272.  * REST response. See {@see wp_is_rest_endpoint()} for that purpose.
  4273.  *
  4274.  * This function should not be called until the {@see 'parse_request'} action, as the constant is only defined then,
  4275.  * even for an actual REST request.
  4276.  *
  4277.  * @since 6.5.0
  4278.  *
  4279.  * @return bool True if it's a WordPress REST API request, false otherwise.
  4280.  */
  4281. function wp_is_serving_rest_request() {
  4282.     return defined'REST_REQUEST' ) && REST_REQUEST;
  4283. }
  4284. /**
  4285.  * Converts smiley code to the icon graphic file equivalent.
  4286.  *
  4287.  * You can turn off smilies, by going to the write setting screen and unchecking
  4288.  * the box, or by setting 'use_smilies' option to false or removing the option.
  4289.  *
  4290.  * Plugins may override the default smiley list by setting the $wpsmiliestrans
  4291.  * to an array, with the key the code the blogger types in and the value the
  4292.  * image file.
  4293.  *
  4294.  * The $wp_smiliessearch global is for the regular expression and is set each
  4295.  * time the function is called.
  4296.  *
  4297.  * The full list of smilies can be found in the function and won't be listed in
  4298.  * the description. Probably should create a Codex page for it, so that it is
  4299.  * available.
  4300.  *
  4301.  * @since 2.2.0
  4302.  *
  4303.  * @global array $wpsmiliestrans
  4304.  * @global array $wp_smiliessearch
  4305.  */
  4306. function smilies_init() {
  4307.     global $wpsmiliestrans$wp_smiliessearch;
  4308.     // Don't bother setting up smilies if they are disabled.
  4309.     if ( ! get_option'use_smilies' ) ) {
  4310.         return;
  4311.     }
  4312.     if ( ! isset( $wpsmiliestrans ) ) {
  4313.         $wpsmiliestrans = array(
  4314.             ':mrgreen:' => 'mrgreen.png',
  4315.             ':neutral:' => "\xf0\x9f\x98\x90",
  4316.             ':twisted:' => "\xf0\x9f\x98\x88",
  4317.             ':arrow:'   => "\xe2\x9e\xa1",
  4318.             ':shock:'   => "\xf0\x9f\x98\xaf",
  4319.             ':smile:'   => "\xf0\x9f\x99\x82",
  4320.             ':???:'     => "\xf0\x9f\x98\x95",
  4321.             ':cool:'    => "\xf0\x9f\x98\x8e",
  4322.             ':evil:'    => "\xf0\x9f\x91\xbf",
  4323.             ':grin:'    => "\xf0\x9f\x98\x80",
  4324.             ':idea:'    => "\xf0\x9f\x92\xa1",
  4325.             ':oops:'    => "\xf0\x9f\x98\xb3",
  4326.             ':razz:'    => "\xf0\x9f\x98\x9b",
  4327.             ':roll:'    => "\xf0\x9f\x99\x84",
  4328.             ':wink:'    => "\xf0\x9f\x98\x89",
  4329.             ':cry:'     => "\xf0\x9f\x98\xa5",
  4330.             ':eek:'     => "\xf0\x9f\x98\xae",
  4331.             ':lol:'     => "\xf0\x9f\x98\x86",
  4332.             ':mad:'     => "\xf0\x9f\x98\xa1",
  4333.             ':sad:'     => "\xf0\x9f\x99\x81",
  4334.             '8-)'       => "\xf0\x9f\x98\x8e",
  4335.             '8-O'       => "\xf0\x9f\x98\xaf",
  4336.             ':-('       => "\xf0\x9f\x99\x81",
  4337.             ':-)'       => "\xf0\x9f\x99\x82",
  4338.             ':-?'       => "\xf0\x9f\x98\x95",
  4339.             ':-D'       => "\xf0\x9f\x98\x80",
  4340.             ':-P'       => "\xf0\x9f\x98\x9b",
  4341.             ':-o'       => "\xf0\x9f\x98\xae",
  4342.             ':-x'       => "\xf0\x9f\x98\xa1",
  4343.             ':-|'       => "\xf0\x9f\x98\x90",
  4344.             ';-)'       => "\xf0\x9f\x98\x89",
  4345.             // This one transformation breaks regular text with frequency.
  4346.             //     '8)' => "\xf0\x9f\x98\x8e",
  4347.             '8O'        => "\xf0\x9f\x98\xaf",
  4348.             ':('        => "\xf0\x9f\x99\x81",
  4349.             ':)'        => "\xf0\x9f\x99\x82",
  4350.             ':?'        => "\xf0\x9f\x98\x95",
  4351.             ':D'        => "\xf0\x9f\x98\x80",
  4352.             ':P'        => "\xf0\x9f\x98\x9b",
  4353.             ':o'        => "\xf0\x9f\x98\xae",
  4354.             ':x'        => "\xf0\x9f\x98\xa1",
  4355.             ':|'        => "\xf0\x9f\x98\x90",
  4356.             ';)'        => "\xf0\x9f\x98\x89",
  4357.             ':!:'       => "\xe2\x9d\x97",
  4358.             ':?:'       => "\xe2\x9d\x93",
  4359.         );
  4360.     }
  4361.     /**
  4362.      * Filters all the smilies.
  4363.      *
  4364.      * This filter must be added before `smilies_init` is run, as
  4365.      * it is normally only run once to setup the smilies regex.
  4366.      *
  4367.      * @since 4.7.0
  4368.      *
  4369.      * @param string[] $wpsmiliestrans List of the smilies' hexadecimal representations, keyed by their smily code.
  4370.      */
  4371.     $wpsmiliestrans apply_filters'smilies'$wpsmiliestrans );
  4372.     if ( count$wpsmiliestrans ) === ) {
  4373.         return;
  4374.     }
  4375.     /*
  4376.      * NOTE: we sort the smilies in reverse key order. This is to make sure
  4377.      * we match the longest possible smilie (:???: vs :?) as the regular
  4378.      * expression used below is first-match
  4379.      */
  4380.     krsort$wpsmiliestrans );
  4381.     $spaces wp_spaces_regexp();
  4382.     // Begin first "subpattern".
  4383.     $wp_smiliessearch '/(?<=' $spaces '|^)';
  4384.     $subchar '';
  4385.     foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
  4386.         $firstchar substr$smiley0);
  4387.         $rest      substr$smiley);
  4388.         // New subpattern?
  4389.         if ( $firstchar !== $subchar ) {
  4390.             if ( '' !== $subchar ) {
  4391.                 $wp_smiliessearch .= ')(?=' $spaces '|$)';  // End previous "subpattern".
  4392.                 $wp_smiliessearch .= '|(?<=' $spaces '|^)'// Begin another "subpattern".
  4393.             }
  4394.             $subchar           $firstchar;
  4395.             $wp_smiliessearch .= preg_quote$firstchar'/' ) . '(?:';
  4396.         } else {
  4397.             $wp_smiliessearch .= '|';
  4398.         }
  4399.         $wp_smiliessearch .= preg_quote$rest'/' );
  4400.     }
  4401.     $wp_smiliessearch .= ')(?=' $spaces '|$)/m';
  4402. }
  4403. /**
  4404.  * Merges user defined arguments into defaults array.
  4405.  *
  4406.  * This function is used throughout WordPress to allow for both string or array
  4407.  * to be merged into another array.
  4408.  *
  4409.  * @since 2.2.0
  4410.  * @since 2.3.0 `$args` can now also be an object.
  4411.  *
  4412.  * @param string|array|object $args     Value to merge with $defaults.
  4413.  * @param array               $defaults Optional. Array that serves as the defaults.
  4414.  *                                      Default empty array.
  4415.  * @return array Merged user defined values with defaults.
  4416.  */
  4417. function wp_parse_args$args$defaults = array() ) {
  4418.     if ( is_object$args ) ) {
  4419.         $parsed_args get_object_vars$args );
  4420.     } elseif ( is_array$args ) ) {
  4421.         $parsed_args =& $args;
  4422.     } else {
  4423.         wp_parse_str$args$parsed_args );
  4424.     }
  4425.     if ( is_array$defaults ) && $defaults ) {
  4426.         return array_merge$defaults$parsed_args );
  4427.     }
  4428.     return $parsed_args;
  4429. }
  4430. /**
  4431.  * Converts a comma- or space-separated list of scalar values to an array.
  4432.  *
  4433.  * @since 5.1.0
  4434.  *
  4435.  * @param array|string $input_list List of values.
  4436.  * @return array Array of values.
  4437.  */
  4438. function wp_parse_list$input_list ) {
  4439.     if ( ! is_array$input_list ) ) {
  4440.         return preg_split'/[\s,]+/'$input_list, -1PREG_SPLIT_NO_EMPTY );
  4441.     }
  4442.     // Validate all entries of the list are scalar.
  4443.     $input_list array_filter$input_list'is_scalar' );
  4444.     return $input_list;
  4445. }
  4446. /**
  4447.  * Cleans up an array, comma- or space-separated list of IDs.
  4448.  *
  4449.  * @since 3.0.0
  4450.  * @since 5.1.0 Refactored to use wp_parse_list().
  4451.  *
  4452.  * @param array|string $input_list List of IDs.
  4453.  * @return int[] Sanitized array of IDs.
  4454.  */
  4455. function wp_parse_id_list$input_list ) {
  4456.     $input_list wp_parse_list$input_list );
  4457.     return array_uniquearray_map'absint'$input_list ) );
  4458. }
  4459. /**
  4460.  * Cleans up an array, comma- or space-separated list of slugs.
  4461.  *
  4462.  * @since 4.7.0
  4463.  * @since 5.1.0 Refactored to use wp_parse_list().
  4464.  *
  4465.  * @param array|string $input_list List of slugs.
  4466.  * @return string[] Sanitized array of slugs.
  4467.  */
  4468. function wp_parse_slug_list$input_list ) {
  4469.     $input_list wp_parse_list$input_list );
  4470.     return array_uniquearray_map'sanitize_title'$input_list ) );
  4471. }
  4472. /**
  4473.  * Extracts a slice of an array, given a list of keys.
  4474.  *
  4475.  * @since 3.1.0
  4476.  *
  4477.  * @param array $input_array The original array.
  4478.  * @param array $keys        The list of keys.
  4479.  * @return array The array slice.
  4480.  */
  4481. function wp_array_slice_assoc$input_array$keys ) {
  4482.     $slice = array();
  4483.     foreach ( $keys as $key ) {
  4484.         if ( isset( $input_array$key ] ) ) {
  4485.             $slice$key ] = $input_array$key ];
  4486.         }
  4487.     }
  4488.     return $slice;
  4489. }
  4490. /**
  4491.  * Sorts the keys of an array alphabetically.
  4492.  *
  4493.  * The array is passed by reference so it doesn't get returned
  4494.  * which mimics the behavior of `ksort()`.
  4495.  *
  4496.  * @since 6.0.0
  4497.  *
  4498.  * @param array $input_array The array to sort, passed by reference.
  4499.  */
  4500. function wp_recursive_ksort( &$input_array ) {
  4501.     foreach ( $input_array as &$value ) {
  4502.         if ( is_array$value ) ) {
  4503.             wp_recursive_ksort$value );
  4504.         }
  4505.     }
  4506.     ksort$input_array );
  4507. }
  4508. /**
  4509.  * Accesses an array in depth based on a path of keys.
  4510.  *
  4511.  * It is the PHP equivalent of JavaScript's `lodash.get()` and mirroring it may help other components
  4512.  * retain some symmetry between client and server implementations.
  4513.  *
  4514.  * Example usage:
  4515.  *
  4516.  *     $input_array = array(
  4517.  *         'a' => array(
  4518.  *             'b' => array(
  4519.  *                 'c' => 1,
  4520.  *             ),
  4521.  *         ),
  4522.  *     );
  4523.  *     _wp_array_get( $input_array, array( 'a', 'b', 'c' ) );
  4524.  *
  4525.  * @internal
  4526.  *
  4527.  * @since 5.6.0
  4528.  * @access private
  4529.  *
  4530.  * @param array $input_array   An array from which we want to retrieve some information.
  4531.  * @param array $path          An array of keys describing the path with which to retrieve information.
  4532.  * @param mixed $default_value Optional. The return value if the path does not exist within the array,
  4533.  *                             or if `$input_array` or `$path` are not arrays. Default null.
  4534.  * @return mixed The value from the path specified.
  4535.  */
  4536. function _wp_array_get$input_array$path$default_value null ) {
  4537.     // Confirm $path is valid.
  4538.     if ( ! is_array$path ) || === count$path ) ) {
  4539.         return $default_value;
  4540.     }
  4541.     foreach ( $path as $path_element ) {
  4542.         if ( ! is_array$input_array ) ) {
  4543.             return $default_value;
  4544.         }
  4545.         if ( is_string$path_element )
  4546.             || is_integer$path_element )
  4547.             || null === $path_element
  4548.         ) {
  4549.             /*
  4550.              * Check if the path element exists in the input array.
  4551.              * We check with `isset()` first, as it is a lot faster
  4552.              * than `array_key_exists()`.
  4553.              */
  4554.             if ( isset( $input_array$path_element ] ) ) {
  4555.                 $input_array $input_array$path_element ];
  4556.                 continue;
  4557.             }
  4558.             /*
  4559.              * If `isset()` returns false, we check with `array_key_exists()`,
  4560.              * which also checks for `null` values.
  4561.              */
  4562.             if ( array_key_exists$path_element$input_array ) ) {
  4563.                 $input_array $input_array$path_element ];
  4564.                 continue;
  4565.             }
  4566.         }
  4567.         return $default_value;
  4568.     }
  4569.     return $input_array;
  4570. }
  4571. /**
  4572.  * Sets an array in depth based on a path of keys.
  4573.  *
  4574.  * It is the PHP equivalent of JavaScript's `lodash.set()` and mirroring it may help other components
  4575.  * retain some symmetry between client and server implementations.
  4576.  *
  4577.  * Example usage:
  4578.  *
  4579.  *     $input_array = array();
  4580.  *     _wp_array_set( $input_array, array( 'a', 'b', 'c', 1 ) );
  4581.  *
  4582.  *     $input_array becomes:
  4583.  *     array(
  4584.  *         'a' => array(
  4585.  *             'b' => array(
  4586.  *                 'c' => 1,
  4587.  *             ),
  4588.  *         ),
  4589.  *     );
  4590.  *
  4591.  * @internal
  4592.  *
  4593.  * @since 5.8.0
  4594.  * @access private
  4595.  *
  4596.  * @param array $input_array An array that we want to mutate to include a specific value in a path.
  4597.  * @param array $path        An array of keys describing the path that we want to mutate.
  4598.  * @param mixed $value       The value that will be set.
  4599.  */
  4600. function _wp_array_set( &$input_array$path$value null ) {
  4601.     // Confirm $input_array is valid.
  4602.     if ( ! is_array$input_array ) ) {
  4603.         return;
  4604.     }
  4605.     // Confirm $path is valid.
  4606.     if ( ! is_array$path ) ) {
  4607.         return;
  4608.     }
  4609.     $path_length count$path );
  4610.     if ( === $path_length ) {
  4611.         return;
  4612.     }
  4613.     foreach ( $path as $path_element ) {
  4614.         if (
  4615.             ! is_string$path_element ) && ! is_integer$path_element ) &&
  4616.             ! is_null$path_element )
  4617.         ) {
  4618.             return;
  4619.         }
  4620.     }
  4621.     for ( $i 0$i $path_length 1; ++$i ) {
  4622.         $path_element $path$i ];
  4623.         if (
  4624.             ! array_key_exists$path_element$input_array ) ||
  4625.             ! is_array$input_array$path_element ] )
  4626.         ) {
  4627.             $input_array$path_element ] = array();
  4628.         }
  4629.         $input_array = &$input_array$path_element ];
  4630.     }
  4631.     $input_array$path$i ] ] = $value;
  4632. }
  4633. /**
  4634.  * This function is trying to replicate what
  4635.  * lodash's kebabCase (JS library) does in the client.
  4636.  *
  4637.  * The reason we need this function is that we do some processing
  4638.  * in both the client and the server (e.g.: we generate
  4639.  * preset classes from preset slugs) that needs to
  4640.  * create the same output.
  4641.  *
  4642.  * We can't remove or update the client's library due to backward compatibility
  4643.  * (some of the output of lodash's kebabCase is saved in the post content).
  4644.  * We have to make the server behave like the client.
  4645.  *
  4646.  * Changes to this function should follow updates in the client
  4647.  * with the same logic.
  4648.  *
  4649.  * @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L14369
  4650.  * @link https://github.com/lodash/lodash/blob/4.17/dist/lodash.js#L278
  4651.  * @link https://github.com/lodash-php/lodash-php/blob/master/src/String/kebabCase.php
  4652.  * @link https://github.com/lodash-php/lodash-php/blob/master/src/internal/unicodeWords.php
  4653.  *
  4654.  * @param string $input_string The string to kebab-case.
  4655.  *
  4656.  * @return string kebab-cased-string.
  4657.  */
  4658. function _wp_to_kebab_case$input_string ) {
  4659.     // Ignore the camelCase names for variables so the names are the same as lodash so comparing and porting new changes is easier.
  4660.     // phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
  4661.     /*
  4662.      * Some notable things we've removed compared to the lodash version are:
  4663.      *
  4664.      * - non-alphanumeric characters: rsAstralRange, rsEmoji, etc
  4665.      * - the groups that processed the apostrophe, as it's removed before passing the string to preg_match: rsApos, rsOptContrLower, and rsOptContrUpper
  4666.      *
  4667.      */
  4668.     /** Used to compose unicode character classes. */
  4669.     $rsLowerRange       'a-z\\xdf-\\xf6\\xf8-\\xff';
  4670.     $rsNonCharRange     '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf';
  4671.     $rsPunctuationRange '\\x{2000}-\\x{206f}';
  4672.     $rsSpaceRange       ' \\t\\x0b\\f\\xa0\\x{feff}\\n\\r\\x{2028}\\x{2029}\\x{1680}\\x{180e}\\x{2000}\\x{2001}\\x{2002}\\x{2003}\\x{2004}\\x{2005}\\x{2006}\\x{2007}\\x{2008}\\x{2009}\\x{200a}\\x{202f}\\x{205f}\\x{3000}';
  4673.     $rsUpperRange       'A-Z\\xc0-\\xd6\\xd8-\\xde';
  4674.     $rsBreakRange       $rsNonCharRange $rsPunctuationRange $rsSpaceRange;
  4675.     /** Used to compose unicode capture groups. */
  4676.     $rsBreak  '[' $rsBreakRange ']';
  4677.     $rsDigits '\\d+'// The last lodash version in GitHub uses a single digit here and expands it when in use.
  4678.     $rsLower  '[' $rsLowerRange ']';
  4679.     $rsMisc   '[^' $rsBreakRange $rsDigits $rsLowerRange $rsUpperRange ']';
  4680.     $rsUpper  '[' $rsUpperRange ']';
  4681.     /** Used to compose unicode regexes. */
  4682.     $rsMiscLower '(?:' $rsLower '|' $rsMisc ')';
  4683.     $rsMiscUpper '(?:' $rsUpper '|' $rsMisc ')';
  4684.     $rsOrdLower  '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])';
  4685.     $rsOrdUpper  '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])';
  4686.     $regexp '/' implode(
  4687.         '|',
  4688.         array(
  4689.             $rsUpper '?' $rsLower '+' '(?=' implode'|', array( $rsBreak$rsUpper'$' ) ) . ')',
  4690.             $rsMiscUpper '+' '(?=' implode'|', array( $rsBreak$rsUpper $rsMiscLower'$' ) ) . ')',
  4691.             $rsUpper '?' $rsMiscLower '+',
  4692.             $rsUpper '+',
  4693.             $rsOrdUpper,
  4694.             $rsOrdLower,
  4695.             $rsDigits,
  4696.         )
  4697.     ) . '/u';
  4698.     preg_match_all$regexpstr_replace"'"''$input_string ), $matches );
  4699.     return strtolowerimplode'-'$matches[0] ) );
  4700.     // phpcs:enable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
  4701. }
  4702. /**
  4703.  * Determines if the variable is a numeric-indexed array.
  4704.  *
  4705.  * @since 4.4.0
  4706.  *
  4707.  * @param mixed $data Variable to check.
  4708.  * @return bool Whether the variable is a list.
  4709.  */
  4710. function wp_is_numeric_array$data ) {
  4711.     if ( ! is_array$data ) ) {
  4712.         return false;
  4713.     }
  4714.     $keys        array_keys$data );
  4715.     $string_keys array_filter$keys'is_string' );
  4716.     return count$string_keys ) === 0;
  4717. }
  4718. /**
  4719.  * Filters a list of objects, based on a set of key => value arguments.
  4720.  *
  4721.  * Retrieves the objects from the list that match the given arguments.
  4722.  * Key represents property name, and value represents property value.
  4723.  *
  4724.  * If an object has more properties than those specified in arguments,
  4725.  * that will not disqualify it. When using the 'AND' operator,
  4726.  * any missing properties will disqualify it.
  4727.  *
  4728.  * When using the `$field` argument, this function can also retrieve
  4729.  * a particular field from all matching objects, whereas wp_list_filter()
  4730.  * only does the filtering.
  4731.  *
  4732.  * @since 3.0.0
  4733.  * @since 4.7.0 Uses `WP_List_Util` class.
  4734.  *
  4735.  * @param array       $input_list An array of objects to filter.
  4736.  * @param array       $args       Optional. An array of key => value arguments to match
  4737.  *                                against each object. Default empty array.
  4738.  * @param string      $operator   Optional. The logical operation to perform. 'AND' means
  4739.  *                                all elements from the array must match. 'OR' means only
  4740.  *                                one element needs to match. 'NOT' means no elements may
  4741.  *                                match. Default 'AND'.
  4742.  * @param bool|string $field      Optional. A field from the object to place instead
  4743.  *                                of the entire object. Default false.
  4744.  * @return array A list of objects or object fields.
  4745.  */
  4746. function wp_filter_object_list$input_list$args = array(), $operator 'and'$field false ) {
  4747.     if ( ! is_array$input_list ) ) {
  4748.         return array();
  4749.     }
  4750.     $util = new WP_List_Util$input_list );
  4751.     $util->filter$args$operator );
  4752.     if ( $field ) {
  4753.         $util->pluck$field );
  4754.     }
  4755.     return $util->get_output();
  4756. }
  4757. /**
  4758.  * Filters a list of objects, based on a set of key => value arguments.
  4759.  *
  4760.  * Retrieves the objects from the list that match the given arguments.
  4761.  * Key represents property name, and value represents property value.
  4762.  *
  4763.  * If an object has more properties than those specified in arguments,
  4764.  * that will not disqualify it. When using the 'AND' operator,
  4765.  * any missing properties will disqualify it.
  4766.  *
  4767.  * If you want to retrieve a particular field from all matching objects,
  4768.  * use wp_filter_object_list() instead.
  4769.  *
  4770.  * @since 3.1.0
  4771.  * @since 4.7.0 Uses `WP_List_Util` class.
  4772.  * @since 5.9.0 Converted into a wrapper for `wp_filter_object_list()`.
  4773.  *
  4774.  * @param array  $input_list An array of objects to filter.
  4775.  * @param array  $args       Optional. An array of key => value arguments to match
  4776.  *                           against each object. Default empty array.
  4777.  * @param string $operator   Optional. The logical operation to perform. 'AND' means
  4778.  *                           all elements from the array must match. 'OR' means only
  4779.  *                           one element needs to match. 'NOT' means no elements may
  4780.  *                           match. Default 'AND'.
  4781.  * @return array Array of found values.
  4782.  */
  4783. function wp_list_filter$input_list$args = array(), $operator 'AND' ) {
  4784.     return wp_filter_object_list$input_list$args$operator );
  4785. }
  4786. /**
  4787.  * Plucks a certain field out of each object or array in an array.
  4788.  *
  4789.  * This has the same functionality and prototype of
  4790.  * array_column() (PHP 5.5) but also supports objects.
  4791.  *
  4792.  * @since 3.1.0
  4793.  * @since 4.0.0 $index_key parameter added.
  4794.  * @since 4.7.0 Uses `WP_List_Util` class.
  4795.  *
  4796.  * @param array      $input_list List of objects or arrays.
  4797.  * @param int|string $field      Field from the object to place instead of the entire object.
  4798.  * @param int|string $index_key  Optional. Field from the object to use as keys for the new array.
  4799.  *                               Default null.
  4800.  * @return array Array of found values. If `$index_key` is set, an array of found values with keys
  4801.  *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
  4802.  *               `$input_list` will be preserved in the results.
  4803.  */
  4804. function wp_list_pluck$input_list$field$index_key null ) {
  4805.     if ( ! is_array$input_list ) ) {
  4806.         return array();
  4807.     }
  4808.     $util = new WP_List_Util$input_list );
  4809.     return $util->pluck$field$index_key );
  4810. }
  4811. /**
  4812.  * Sorts an array of objects or arrays based on one or more orderby arguments.
  4813.  *
  4814.  * @since 4.7.0
  4815.  *
  4816.  * @param array        $input_list    An array of objects or arrays to sort.
  4817.  * @param string|array $orderby       Optional. Either the field name to order by or an array
  4818.  *                                    of multiple orderby fields as `$orderby => $order`.
  4819.  *                                    Default empty array.
  4820.  * @param string       $order         Optional. Either 'ASC' or 'DESC'. Only used if `$orderby`
  4821.  *                                    is a string. Default 'ASC'.
  4822.  * @param bool         $preserve_keys Optional. Whether to preserve keys. Default false.
  4823.  * @return array The sorted array.
  4824.  */
  4825. function wp_list_sort$input_list$orderby = array(), $order 'ASC'$preserve_keys false ) {
  4826.     if ( ! is_array$input_list ) ) {
  4827.         return array();
  4828.     }
  4829.     $util = new WP_List_Util$input_list );
  4830.     return $util->sort$orderby$order$preserve_keys );
  4831. }
  4832. /**
  4833.  * Determines if Widgets library should be loaded.
  4834.  *
  4835.  * Checks to make sure that the widgets library hasn't already been loaded.
  4836.  * If it hasn't, then it will load the widgets library and run an action hook.
  4837.  *
  4838.  * @since 2.2.0
  4839.  */
  4840. function wp_maybe_load_widgets() {
  4841.     /**
  4842.      * Filters whether to load the Widgets library.
  4843.      *
  4844.      * Returning a falsey value from the filter will effectively short-circuit
  4845.      * the Widgets library from loading.
  4846.      *
  4847.      * @since 2.8.0
  4848.      *
  4849.      * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
  4850.      *                                    Default true.
  4851.      */
  4852.     if ( ! apply_filters'load_default_widgets'true ) ) {
  4853.         return;
  4854.     }
  4855.     require_once ABSPATH WPINC '/default-widgets.php';
  4856.     add_action'_admin_menu''wp_widgets_add_menu' );
  4857. }
  4858. /**
  4859.  * Appends the Widgets menu to the themes main menu.
  4860.  *
  4861.  * @since 2.2.0
  4862.  * @since 5.9.3 Don't specify menu order when the active theme is a block theme.
  4863.  *
  4864.  * @global array $submenu
  4865.  */
  4866. function wp_widgets_add_menu() {
  4867.     global $submenu;
  4868.     if ( ! current_theme_supports'widgets' ) ) {
  4869.         return;
  4870.     }
  4871.     $menu_name __'Widgets' );
  4872.     if ( wp_is_block_theme() ) {
  4873.         $submenu['themes.php'][] = array( $menu_name'edit_theme_options''widgets.php' );
  4874.     } else {
  4875.         $submenu['themes.php'][8] = array( $menu_name'edit_theme_options''widgets.php' );
  4876.     }
  4877.     ksort$submenu['themes.php'], SORT_NUMERIC );
  4878. }
  4879. /**
  4880.  * Flushes all output buffers for PHP 5.2.
  4881.  *
  4882.  * Make sure all output buffers are flushed before our singletons are destroyed.
  4883.  *
  4884.  * @since 2.2.0
  4885.  */
  4886. function wp_ob_end_flush_all() {
  4887.     $levels ob_get_level();
  4888.     for ( $i 0$i $levels$i++ ) {
  4889.         ob_end_flush();
  4890.     }
  4891. }
  4892. /**
  4893.  * Loads custom DB error or display WordPress DB error.
  4894.  *
  4895.  * If a file exists in the wp-content directory named db-error.php, then it will
  4896.  * be loaded instead of displaying the WordPress DB error. If it is not found,
  4897.  * then the WordPress DB error will be displayed instead.
  4898.  *
  4899.  * The WordPress DB error sets the HTTP status header to 500 to try to prevent
  4900.  * search engines from caching the message. Custom DB messages should do the
  4901.  * same.
  4902.  *
  4903.  * This function was backported to WordPress 2.3.2, but originally was added
  4904.  * in WordPress 2.5.0.
  4905.  *
  4906.  * @since 2.3.2
  4907.  *
  4908.  * @global wpdb $wpdb WordPress database abstraction object.
  4909.  */
  4910. function dead_db() {
  4911.     global $wpdb;
  4912.     wp_load_translations_early();
  4913.     // Load custom DB error template, if present.
  4914.     if ( file_existsWP_CONTENT_DIR '/db-error.php' ) ) {
  4915.         require_once WP_CONTENT_DIR '/db-error.php';
  4916.         die();
  4917.     }
  4918.     // If installing or in the admin, provide the verbose message.
  4919.     if ( wp_installing() || defined'WP_ADMIN' ) ) {
  4920.         wp_die$wpdb->error );
  4921.     }
  4922.     // Otherwise, be terse.
  4923.     wp_die'<h1>' __'Error establishing a database connection' ) . '</h1>'__'Database Error' ) );
  4924. }
  4925. /**
  4926.  * Marks a function as deprecated and inform when it has been used.
  4927.  *
  4928.  * There is a {@see 'deprecated_function_run'} hook that will be called that can be used
  4929.  * to get the backtrace up to what file and function called the deprecated function.
  4930.  *
  4931.  * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  4932.  *
  4933.  * This function is to be used in every function that is deprecated.
  4934.  *
  4935.  * @since 2.5.0
  4936.  * @since 5.4.0 This function is no longer marked as "private".
  4937.  * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
  4938.  *
  4939.  * @param string $function_name The function that was called.
  4940.  * @param string $version       The version of WordPress that deprecated the function.
  4941.  * @param string $replacement   Optional. The function that should have been called. Default empty string.
  4942.  */
  4943. function _deprecated_function$function_name$version$replacement '' ) {
  4944.     /**
  4945.      * Fires when a deprecated function is called.
  4946.      *
  4947.      * @since 2.5.0
  4948.      *
  4949.      * @param string $function_name The function that was called.
  4950.      * @param string $replacement   The function that should have been called.
  4951.      * @param string $version       The version of WordPress that deprecated the function.
  4952.      */
  4953.     do_action'deprecated_function_run'$function_name$replacement$version );
  4954.     /**
  4955.      * Filters whether to trigger an error for deprecated functions.
  4956.      *
  4957.      * @since 2.5.0
  4958.      *
  4959.      * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
  4960.      */
  4961.     if ( WP_DEBUG && apply_filters'deprecated_function_trigger_error'true ) ) {
  4962.         if ( function_exists'__' ) ) {
  4963.             if ( $replacement ) {
  4964.                 $message sprintf(
  4965.                     /* translators: 1: PHP function name, 2: Version number, 3: Alternative function name. */
  4966.                     __'Function %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
  4967.                     $function_name,
  4968.                     $version,
  4969.                     $replacement
  4970.                 );
  4971.             } else {
  4972.                 $message sprintf(
  4973.                     /* translators: 1: PHP function name, 2: Version number. */
  4974.                     __'Function %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
  4975.                     $function_name,
  4976.                     $version
  4977.                 );
  4978.             }
  4979.         } else {
  4980.             if ( $replacement ) {
  4981.                 $message sprintf(
  4982.                     'Function %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
  4983.                     $function_name,
  4984.                     $version,
  4985.                     $replacement
  4986.                 );
  4987.             } else {
  4988.                 $message sprintf(
  4989.                     'Function %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
  4990.                     $function_name,
  4991.                     $version
  4992.                 );
  4993.             }
  4994.         }
  4995.         wp_trigger_error''$messageE_USER_DEPRECATED );
  4996.     }
  4997. }
  4998. /**
  4999.  * Marks a constructor as deprecated and informs when it has been used.
  5000.  *
  5001.  * Similar to _deprecated_function(), but with different strings. Used to
  5002.  * remove PHP4-style constructors.
  5003.  *
  5004.  * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  5005.  *
  5006.  * This function is to be used in every PHP4-style constructor method that is deprecated.
  5007.  *
  5008.  * @since 4.3.0
  5009.  * @since 4.5.0 Added the `$parent_class` parameter.
  5010.  * @since 5.4.0 This function is no longer marked as "private".
  5011.  * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
  5012.  *
  5013.  * @param string $class_name   The class containing the deprecated constructor.
  5014.  * @param string $version      The version of WordPress that deprecated the function.
  5015.  * @param string $parent_class Optional. The parent class calling the deprecated constructor.
  5016.  *                             Default empty string.
  5017.  */
  5018. function _deprecated_constructor$class_name$version$parent_class '' ) {
  5019.     /**
  5020.      * Fires when a deprecated constructor is called.
  5021.      *
  5022.      * @since 4.3.0
  5023.      * @since 4.5.0 Added the `$parent_class` parameter.
  5024.      *
  5025.      * @param string $class_name   The class containing the deprecated constructor.
  5026.      * @param string $version      The version of WordPress that deprecated the function.
  5027.      * @param string $parent_class The parent class calling the deprecated constructor.
  5028.      */
  5029.     do_action'deprecated_constructor_run'$class_name$version$parent_class );
  5030.     /**
  5031.      * Filters whether to trigger an error for deprecated functions.
  5032.      *
  5033.      * `WP_DEBUG` must be true in addition to the filter evaluating to true.
  5034.      *
  5035.      * @since 4.3.0
  5036.      *
  5037.      * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
  5038.      */
  5039.     if ( WP_DEBUG && apply_filters'deprecated_constructor_trigger_error'true ) ) {
  5040.         if ( function_exists'__' ) ) {
  5041.             if ( $parent_class ) {
  5042.                 $message sprintf(
  5043.                     /* translators: 1: PHP class name, 2: PHP parent class name, 3: Version number, 4: __construct() method. */
  5044.                     __'The called constructor method for %1$s class in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
  5045.                     $class_name,
  5046.                     $parent_class,
  5047.                     $version,
  5048.                     '<code>__construct()</code>'
  5049.                 );
  5050.             } else {
  5051.                 $message sprintf(
  5052.                     /* translators: 1: PHP class name, 2: Version number, 3: __construct() method. */
  5053.                     __'The called constructor method for %1$s class is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
  5054.                     $class_name,
  5055.                     $version,
  5056.                     '<code>__construct()</code>'
  5057.                 );
  5058.             }
  5059.         } else {
  5060.             if ( $parent_class ) {
  5061.                 $message sprintf(
  5062.                     'The called constructor method for %1$s class in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
  5063.                     $class_name,
  5064.                     $parent_class,
  5065.                     $version,
  5066.                     '<code>__construct()</code>'
  5067.                 );
  5068.             } else {
  5069.                 $message sprintf(
  5070.                     'The called constructor method for %1$s class is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
  5071.                     $class_name,
  5072.                     $version,
  5073.                     '<code>__construct()</code>'
  5074.                 );
  5075.             }
  5076.         }
  5077.         wp_trigger_error''$messageE_USER_DEPRECATED );
  5078.     }
  5079. }
  5080. /**
  5081.  * Marks a class as deprecated and informs when it has been used.
  5082.  *
  5083.  * There is a {@see 'deprecated_class_run'} hook that will be called that can be used
  5084.  * to get the backtrace up to what file and function called the deprecated class.
  5085.  *
  5086.  * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  5087.  *
  5088.  * This function is to be used in the class constructor for every deprecated class.
  5089.  * See {@see _deprecated_constructor()} for deprecating PHP4-style constructors.
  5090.  *
  5091.  * @since 6.4.0
  5092.  *
  5093.  * @param string $class_name  The name of the class being instantiated.
  5094.  * @param string $version     The version of WordPress that deprecated the class.
  5095.  * @param string $replacement Optional. The class or function that should have been called.
  5096.  *                            Default empty string.
  5097.  */
  5098. function _deprecated_class$class_name$version$replacement '' ) {
  5099.     /**
  5100.      * Fires when a deprecated class is called.
  5101.      *
  5102.      * @since 6.4.0
  5103.      *
  5104.      * @param string $class_name  The name of the class being instantiated.
  5105.      * @param string $replacement The class or function that should have been called.
  5106.      * @param string $version     The version of WordPress that deprecated the class.
  5107.      */
  5108.     do_action'deprecated_class_run'$class_name$replacement$version );
  5109.     /**
  5110.      * Filters whether to trigger an error for a deprecated class.
  5111.      *
  5112.      * @since 6.4.0
  5113.      *
  5114.      * @param bool $trigger Whether to trigger an error for a deprecated class. Default true.
  5115.      */
  5116.     if ( WP_DEBUG && apply_filters'deprecated_class_trigger_error'true ) ) {
  5117.         if ( function_exists'__' ) ) {
  5118.             if ( $replacement ) {
  5119.                 $message sprintf(
  5120.                     /* translators: 1: PHP class name, 2: Version number, 3: Alternative class or function name. */
  5121.                     __'Class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
  5122.                     $class_name,
  5123.                     $version,
  5124.                     $replacement
  5125.                 );
  5126.             } else {
  5127.                 $message sprintf(
  5128.                     /* translators: 1: PHP class name, 2: Version number. */
  5129.                     __'Class %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
  5130.                     $class_name,
  5131.                     $version
  5132.                 );
  5133.             }
  5134.         } else {
  5135.             if ( $replacement ) {
  5136.                 $message sprintf(
  5137.                     'Class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
  5138.                     $class_name,
  5139.                     $version,
  5140.                     $replacement
  5141.                 );
  5142.             } else {
  5143.                 $message sprintf(
  5144.                     'Class %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
  5145.                     $class_name,
  5146.                     $version
  5147.                 );
  5148.             }
  5149.         }
  5150.         wp_trigger_error''$messageE_USER_DEPRECATED );
  5151.     }
  5152. }
  5153. /**
  5154.  * Marks a file as deprecated and inform when it has been used.
  5155.  *
  5156.  * There is a {@see 'deprecated_file_included'} hook that will be called that can be used
  5157.  * to get the backtrace up to what file and function included the deprecated file.
  5158.  *
  5159.  * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  5160.  *
  5161.  * This function is to be used in every file that is deprecated.
  5162.  *
  5163.  * @since 2.5.0
  5164.  * @since 5.4.0 This function is no longer marked as "private".
  5165.  * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
  5166.  *
  5167.  * @param string $file        The file that was included.
  5168.  * @param string $version     The version of WordPress that deprecated the file.
  5169.  * @param string $replacement Optional. The file that should have been included based on ABSPATH.
  5170.  *                            Default empty string.
  5171.  * @param string $message     Optional. A message regarding the change. Default empty string.
  5172.  */
  5173. function _deprecated_file$file$version$replacement ''$message '' ) {
  5174.     /**
  5175.      * Fires when a deprecated file is called.
  5176.      *
  5177.      * @since 2.5.0
  5178.      *
  5179.      * @param string $file        The file that was called.
  5180.      * @param string $replacement The file that should have been included based on ABSPATH.
  5181.      * @param string $version     The version of WordPress that deprecated the file.
  5182.      * @param string $message     A message regarding the change.
  5183.      */
  5184.     do_action'deprecated_file_included'$file$replacement$version$message );
  5185.     /**
  5186.      * Filters whether to trigger an error for deprecated files.
  5187.      *
  5188.      * @since 2.5.0
  5189.      *
  5190.      * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
  5191.      */
  5192.     if ( WP_DEBUG && apply_filters'deprecated_file_trigger_error'true ) ) {
  5193.         $message = empty( $message ) ? '' ' ' $message;
  5194.         if ( function_exists'__' ) ) {
  5195.             if ( $replacement ) {
  5196.                 $message sprintf(
  5197.                     /* translators: 1: PHP file name, 2: Version number, 3: Alternative file name. */
  5198.                     __'File %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
  5199.                     $file,
  5200.                     $version,
  5201.                     $replacement
  5202.                 ) . $message;
  5203.             } else {
  5204.                 $message sprintf(
  5205.                     /* translators: 1: PHP file name, 2: Version number. */
  5206.                     __'File %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
  5207.                     $file,
  5208.                     $version
  5209.                 ) . $message;
  5210.             }
  5211.         } else {
  5212.             if ( $replacement ) {
  5213.                 $message sprintf(
  5214.                     'File %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
  5215.                     $file,
  5216.                     $version,
  5217.                     $replacement
  5218.                 );
  5219.             } else {
  5220.                 $message sprintf(
  5221.                     'File %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.',
  5222.                     $file,
  5223.                     $version
  5224.                 ) . $message;
  5225.             }
  5226.         }
  5227.         wp_trigger_error''$messageE_USER_DEPRECATED );
  5228.     }
  5229. }
  5230. /**
  5231.  * Marks a function argument as deprecated and inform when it has been used.
  5232.  *
  5233.  * This function is to be used whenever a deprecated function argument is used.
  5234.  * Before this function is called, the argument must be checked for whether it was
  5235.  * used by comparing it to its default value or evaluating whether it is empty.
  5236.  *
  5237.  * For example:
  5238.  *
  5239.  *     if ( ! empty( $deprecated ) ) {
  5240.  *         _deprecated_argument( __FUNCTION__, '3.0.0' );
  5241.  *     }
  5242.  *
  5243.  * There is a {@see 'deprecated_argument_run'} hook that will be called that can be used
  5244.  * to get the backtrace up to what file and function used the deprecated argument.
  5245.  *
  5246.  * The current behavior is to trigger a user error if WP_DEBUG is true.
  5247.  *
  5248.  * @since 3.0.0
  5249.  * @since 5.4.0 This function is no longer marked as "private".
  5250.  * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
  5251.  *
  5252.  * @param string $function_name The function that was called.
  5253.  * @param string $version       The version of WordPress that deprecated the argument used.
  5254.  * @param string $message       Optional. A message regarding the change. Default empty string.
  5255.  */
  5256. function _deprecated_argument$function_name$version$message '' ) {
  5257.     /**
  5258.      * Fires when a deprecated argument is called.
  5259.      *
  5260.      * @since 3.0.0
  5261.      *
  5262.      * @param string $function_name The function that was called.
  5263.      * @param string $message       A message regarding the change.
  5264.      * @param string $version       The version of WordPress that deprecated the argument used.
  5265.      */
  5266.     do_action'deprecated_argument_run'$function_name$message$version );
  5267.     /**
  5268.      * Filters whether to trigger an error for deprecated arguments.
  5269.      *
  5270.      * @since 3.0.0
  5271.      *
  5272.      * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
  5273.      */
  5274.     if ( WP_DEBUG && apply_filters'deprecated_argument_trigger_error'true ) ) {
  5275.         if ( function_exists'__' ) ) {
  5276.             if ( $message ) {
  5277.                 $message sprintf(
  5278.                     /* translators: 1: PHP function name, 2: Version number, 3: Optional message regarding the change. */
  5279.                     __'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s' ),
  5280.                     $function_name,
  5281.                     $version,
  5282.                     $message
  5283.                 );
  5284.             } else {
  5285.                 $message sprintf(
  5286.                     /* translators: 1: PHP function name, 2: Version number. */
  5287.                     __'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
  5288.                     $function_name,
  5289.                     $version
  5290.                 );
  5291.             }
  5292.         } else {
  5293.             if ( $message ) {
  5294.                 $message sprintf(
  5295.                     'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s',
  5296.                     $function_name,
  5297.                     $version,
  5298.                     $message
  5299.                 );
  5300.             } else {
  5301.                 $message sprintf(
  5302.                     'Function %1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.',
  5303.                     $function_name,
  5304.                     $version
  5305.                 );
  5306.             }
  5307.         }
  5308.         wp_trigger_error''$messageE_USER_DEPRECATED );
  5309.     }
  5310. }
  5311. /**
  5312.  * Marks a deprecated action or filter hook as deprecated and throws a notice.
  5313.  *
  5314.  * Use the {@see 'deprecated_hook_run'} action to get the backtrace describing where
  5315.  * the deprecated hook was called.
  5316.  *
  5317.  * Default behavior is to trigger a user error if `WP_DEBUG` is true.
  5318.  *
  5319.  * This function is called by the do_action_deprecated() and apply_filters_deprecated()
  5320.  * functions, and so generally does not need to be called directly.
  5321.  *
  5322.  * @since 4.6.0
  5323.  * @since 5.4.0 The error type is now classified as E_USER_DEPRECATED (used to default to E_USER_NOTICE).
  5324.  * @access private
  5325.  *
  5326.  * @param string $hook        The hook that was used.
  5327.  * @param string $version     The version of WordPress that deprecated the hook.
  5328.  * @param string $replacement Optional. The hook that should have been used. Default empty string.
  5329.  * @param string $message     Optional. A message regarding the change. Default empty.
  5330.  */
  5331. function _deprecated_hook$hook$version$replacement ''$message '' ) {
  5332.     /**
  5333.      * Fires when a deprecated hook is called.
  5334.      *
  5335.      * @since 4.6.0
  5336.      *
  5337.      * @param string $hook        The hook that was called.
  5338.      * @param string $replacement The hook that should be used as a replacement.
  5339.      * @param string $version     The version of WordPress that deprecated the argument used.
  5340.      * @param string $message     A message regarding the change.
  5341.      */
  5342.     do_action'deprecated_hook_run'$hook$replacement$version$message );
  5343.     /**
  5344.      * Filters whether to trigger deprecated hook errors.
  5345.      *
  5346.      * @since 4.6.0
  5347.      *
  5348.      * @param bool $trigger Whether to trigger deprecated hook errors. Requires
  5349.      *                      `WP_DEBUG` to be defined true.
  5350.      */
  5351.     if ( WP_DEBUG && apply_filters'deprecated_hook_trigger_error'true ) ) {
  5352.         $message = empty( $message ) ? '' ' ' $message;
  5353.         if ( $replacement ) {
  5354.             $message sprintf(
  5355.                 /* translators: 1: WordPress hook name, 2: Version number, 3: Alternative hook name. */
  5356.                 __'Hook %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
  5357.                 $hook,
  5358.                 $version,
  5359.                 $replacement
  5360.             ) . $message;
  5361.         } else {
  5362.             $message sprintf(
  5363.                 /* translators: 1: WordPress hook name, 2: Version number. */
  5364.                 __'Hook %1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ),
  5365.                 $hook,
  5366.                 $version
  5367.             ) . $message;
  5368.         }
  5369.         wp_trigger_error''$messageE_USER_DEPRECATED );
  5370.     }
  5371. }
  5372. /**
  5373.  * Marks something as being incorrectly called.
  5374.  *
  5375.  * There is a {@see 'doing_it_wrong_run'} hook that will be called that can be used
  5376.  * to get the backtrace up to what file and function called the deprecated function.
  5377.  *
  5378.  * The current behavior is to trigger a user error if `WP_DEBUG` is true.
  5379.  *
  5380.  * @since 3.1.0
  5381.  * @since 5.4.0 This function is no longer marked as "private".
  5382.  *
  5383.  * @param string $function_name The function that was called.
  5384.  * @param string $message       A message explaining what has been done incorrectly.
  5385.  * @param string $version       The version of WordPress where the message was added.
  5386.  */
  5387. function _doing_it_wrong$function_name$message$version ) {
  5388.     /**
  5389.      * Fires when the given function is being used incorrectly.
  5390.      *
  5391.      * @since 3.1.0
  5392.      *
  5393.      * @param string $function_name The function that was called.
  5394.      * @param string $message       A message explaining what has been done incorrectly.
  5395.      * @param string $version       The version of WordPress where the message was added.
  5396.      */
  5397.     do_action'doing_it_wrong_run'$function_name$message$version );
  5398.     /**
  5399.      * Filters whether to trigger an error for _doing_it_wrong() calls.
  5400.      *
  5401.      * @since 3.1.0
  5402.      * @since 5.1.0 Added the $function_name, $message and $version parameters.
  5403.      *
  5404.      * @param bool   $trigger       Whether to trigger the error for _doing_it_wrong() calls. Default true.
  5405.      * @param string $function_name The function that was called.
  5406.      * @param string $message       A message explaining what has been done incorrectly.
  5407.      * @param string $version       The version of WordPress where the message was added.
  5408.      */
  5409.     if ( WP_DEBUG && apply_filters'doing_it_wrong_trigger_error'true$function_name$message$version ) ) {
  5410.         if ( function_exists'__' ) ) {
  5411.             if ( $version ) {
  5412.                 /* translators: %s: Version number. */
  5413.                 $version sprintf__'(This message was added in version %s.)' ), $version );
  5414.             }
  5415.             $message .= ' ' sprintf(
  5416.                 /* translators: %s: Documentation URL. */
  5417.                 __'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
  5418.                 __'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/' )
  5419.             );
  5420.             $message sprintf(
  5421.                 /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: WordPress version number. */
  5422.                 __'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s' ),
  5423.                 $function_name,
  5424.                 $message,
  5425.                 $version
  5426.             );
  5427.         } else {
  5428.             if ( $version ) {
  5429.                 $version sprintf'(This message was added in version %s.)'$version );
  5430.             }
  5431.             $message .= sprintf(
  5432.                 ' Please see <a href="%s">Debugging in WordPress</a> for more information.',
  5433.                 'https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/'
  5434.             );
  5435.             $message sprintf(
  5436.                 'Function %1$s was called <strong>incorrectly</strong>. %2$s %3$s',
  5437.                 $function_name,
  5438.                 $message,
  5439.                 $version
  5440.             );
  5441.         }
  5442.         wp_trigger_error''$message );
  5443.     }
  5444. }
  5445. /**
  5446.  * Generates a user-level error/warning/notice/deprecation message.
  5447.  *
  5448.  * Generates the message when `WP_DEBUG` is true.
  5449.  *
  5450.  * @since 6.4.0
  5451.  *
  5452.  * @param string $function_name The function that triggered the error.
  5453.  * @param string $message       The message explaining the error.
  5454.  *                              The message can contain allowed HTML 'a' (with href), 'code',
  5455.  *                              'br', 'em', and 'strong' tags and http or https protocols.
  5456.  *                              If it contains other HTML tags or protocols, the message should be escaped
  5457.  *                              before passing to this function to avoid being stripped {@see wp_kses()}.
  5458.  * @param int    $error_level   Optional. The designated error type for this error.
  5459.  *                              Only works with E_USER family of constants. Default E_USER_NOTICE.
  5460.  */
  5461. function wp_trigger_error$function_name$message$error_level E_USER_NOTICE ) {
  5462.     // Bail out if WP_DEBUG is not turned on.
  5463.     if ( ! WP_DEBUG ) {
  5464.         return;
  5465.     }
  5466.     /**
  5467.      * Fires when the given function triggers a user-level error/warning/notice/deprecation message.
  5468.      *
  5469.      * Can be used for debug backtracking.
  5470.      *
  5471.      * @since 6.4.0
  5472.      *
  5473.      * @param string $function_name The function that was called.
  5474.      * @param string $message       A message explaining what has been done incorrectly.
  5475.      * @param int    $error_level   The designated error type for this error.
  5476.      */
  5477.     do_action'wp_trigger_error_run'$function_name$message$error_level );
  5478.     if ( ! empty( $function_name ) ) {
  5479.         $message sprintf'%s(): %s'$function_name$message );
  5480.     }
  5481.     $message wp_kses(
  5482.         $message,
  5483.         array(
  5484.             'a'      => array( 'href' => true ),
  5485.             'br'     => array(),
  5486.             'code'   => array(),
  5487.             'em'     => array(),
  5488.             'strong' => array(),
  5489.         ),
  5490.         array( 'http''https' )
  5491.     );
  5492.     if ( E_USER_ERROR === $error_level ) {
  5493.         throw new WP_Exception$message );
  5494.     }
  5495.     trigger_error$message$error_level );
  5496. }
  5497. /**
  5498.  * Determines whether the server is running an earlier than 1.5.0 version of lighttpd.
  5499.  *
  5500.  * @since 2.5.0
  5501.  *
  5502.  * @return bool Whether the server is running lighttpd < 1.5.0.
  5503.  */
  5504. function is_lighttpd_before_150() {
  5505.     $server_parts    explode'/', isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
  5506.     $server_parts[1] = isset( $server_parts[1] ) ? $server_parts[1] : '';
  5507.     return ( 'lighttpd' === $server_parts[0] && -=== version_compare$server_parts[1], '1.5.0' ) );
  5508. }
  5509. /**
  5510.  * Determines whether the specified module exist in the Apache config.
  5511.  *
  5512.  * @since 2.5.0
  5513.  *
  5514.  * @global bool $is_apache
  5515.  *
  5516.  * @param string $mod           The module, e.g. mod_rewrite.
  5517.  * @param bool   $default_value Optional. The default return value if the module is not found. Default false.
  5518.  * @return bool Whether the specified module is loaded.
  5519.  */
  5520. function apache_mod_loaded$mod$default_value false ) {
  5521.     global $is_apache;
  5522.     if ( ! $is_apache ) {
  5523.         return false;
  5524.     }
  5525.     $loaded_mods = array();
  5526.     if ( function_exists'apache_get_modules' ) ) {
  5527.         $loaded_mods apache_get_modules();
  5528.         if ( in_array$mod$loaded_modstrue ) ) {
  5529.             return true;
  5530.         }
  5531.     }
  5532.     if ( empty( $loaded_mods )
  5533.         && function_exists'phpinfo' )
  5534.         && ! str_containsini_get'disable_functions' ), 'phpinfo' )
  5535.     ) {
  5536.         ob_start();
  5537.         phpinfoINFO_MODULES );
  5538.         $phpinfo ob_get_clean();
  5539.         if ( str_contains$phpinfo$mod ) ) {
  5540.             return true;
  5541.         }
  5542.     }
  5543.     return $default_value;
  5544. }
  5545. /**
  5546.  * Checks if IIS 7+ supports pretty permalinks.
  5547.  *
  5548.  * @since 2.8.0
  5549.  *
  5550.  * @global bool $is_iis7
  5551.  *
  5552.  * @return bool Whether IIS7 supports permalinks.
  5553.  */
  5554. function iis7_supports_permalinks() {
  5555.     global $is_iis7;
  5556.     $supports_permalinks false;
  5557.     if ( $is_iis7 ) {
  5558.         /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
  5559.          * easily update the xml configuration file, hence we just bail out and tell user that
  5560.          * pretty permalinks cannot be used.
  5561.          *
  5562.          * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the website. When
  5563.          * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
  5564.          * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
  5565.          * via ISAPI then pretty permalinks will not work.
  5566.          */
  5567.         $supports_permalinks class_exists'DOMDocument'false ) && isset( $_SERVER['IIS_UrlRewriteModule'] ) && ( 'cgi-fcgi' === PHP_SAPI );
  5568.     }
  5569.     /**
  5570.      * Filters whether IIS 7+ supports pretty permalinks.
  5571.      *
  5572.      * @since 2.8.0
  5573.      *
  5574.      * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
  5575.      */
  5576.     return apply_filters'iis7_supports_permalinks'$supports_permalinks );
  5577. }
  5578. /**
  5579.  * Validates a file name and path against an allowed set of rules.
  5580.  *
  5581.  * A return value of `1` means the file path contains directory traversal.
  5582.  *
  5583.  * A return value of `2` means the file path contains a Windows drive path.
  5584.  *
  5585.  * A return value of `3` means the file is not in the allowed files list.
  5586.  *
  5587.  * @since 1.2.0
  5588.  *
  5589.  * @param string   $file          File path.
  5590.  * @param string[] $allowed_files Optional. Array of allowed files. Default empty array.
  5591.  * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
  5592.  */
  5593. function validate_file$file$allowed_files = array() ) {
  5594.     if ( ! is_scalar$file ) || '' === $file ) {
  5595.         return 0;
  5596.     }
  5597.     // Normalize path for Windows servers.
  5598.     $file wp_normalize_path$file );
  5599.     // Normalize path for $allowed_files as well so it's an apples to apples comparison.
  5600.     $allowed_files array_map'wp_normalize_path'$allowed_files );
  5601.     // `../` on its own is not allowed:
  5602.     if ( '../' === $file ) {
  5603.         return 1;
  5604.     }
  5605.     // More than one occurrence of `../` is not allowed:
  5606.     if ( preg_match_all'#\.\./#'$file$matchesPREG_SET_ORDER ) && ( count$matches ) > ) ) {
  5607.         return 1;
  5608.     }
  5609.     // `../` which does not occur at the end of the path is not allowed:
  5610.     if ( str_contains$file'../' ) && '../' !== mb_substr$file, -3) ) {
  5611.         return 1;
  5612.     }
  5613.     // Files not in the allowed file list are not allowed:
  5614.     if ( ! empty( $allowed_files ) && ! in_array$file$allowed_filestrue ) ) {
  5615.         return 3;
  5616.     }
  5617.     // Absolute Windows drive paths are not allowed:
  5618.     if ( ':' === substr$file1) ) {
  5619.         return 2;
  5620.     }
  5621.     return 0;
  5622. }
  5623. /**
  5624.  * Determines whether to force SSL used for the Administration Screens.
  5625.  *
  5626.  * @since 2.6.0
  5627.  *
  5628.  * @param string|bool|null $force Optional. Whether to force SSL in admin screens. Default null.
  5629.  * @return bool True if forced, false if not forced.
  5630.  */
  5631. function force_ssl_admin$force null ) {
  5632.     static $forced false;
  5633.     if ( ! is_null$force ) ) {
  5634.         $old_forced $forced;
  5635.         $forced     = (bool) $force;
  5636.         return $old_forced;
  5637.     }
  5638.     return $forced;
  5639. }
  5640. /**
  5641.  * Guesses the URL for the site.
  5642.  *
  5643.  * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
  5644.  * directory.
  5645.  *
  5646.  * @since 2.6.0
  5647.  *
  5648.  * @return string The guessed URL.
  5649.  */
  5650. function wp_guess_url() {
  5651.     if ( defined'WP_SITEURL' ) && '' !== WP_SITEURL ) {
  5652.         $url WP_SITEURL;
  5653.     } else {
  5654.         $abspath_fix         str_replace'\\''/'ABSPATH );
  5655.         $script_filename_dir dirname$_SERVER['SCRIPT_FILENAME'] );
  5656.         // The request is for the admin.
  5657.         if ( str_contains$_SERVER['REQUEST_URI'], 'wp-admin' ) || str_contains$_SERVER['REQUEST_URI'], 'wp-login.php' ) ) {
  5658.             $path preg_replace'#/(wp-admin/?.*|wp-login\.php.*)#i'''$_SERVER['REQUEST_URI'] );
  5659.             // The request is for a file in ABSPATH.
  5660.         } elseif ( $script_filename_dir '/' === $abspath_fix ) {
  5661.             // Strip off any file/query params in the path.
  5662.             $path preg_replace'#/[^/]*$#i'''$_SERVER['PHP_SELF'] );
  5663.         } else {
  5664.             if ( str_contains$_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
  5665.                 // Request is hitting a file inside ABSPATH.
  5666.                 $directory str_replaceABSPATH''$script_filename_dir );
  5667.                 // Strip off the subdirectory, and any file/query params.
  5668.                 $path preg_replace'#/' preg_quote$directory'#' ) . '/[^/]*$#i'''$_SERVER['REQUEST_URI'] );
  5669.             } elseif ( str_contains$abspath_fix$script_filename_dir ) ) {
  5670.                 // Request is hitting a file above ABSPATH.
  5671.                 $subdirectory substr$abspath_fixstrpos$abspath_fix$script_filename_dir ) + strlen$script_filename_dir ) );
  5672.                 // Strip off any file/query params from the path, appending the subdirectory to the installation.
  5673.                 $path preg_replace'#/[^/]*$#i'''$_SERVER['REQUEST_URI'] ) . $subdirectory;
  5674.             } else {
  5675.                 $path $_SERVER['REQUEST_URI'];
  5676.             }
  5677.         }
  5678.         $schema is_ssl() ? 'https://' 'http://'// set_url_scheme() is not defined yet.
  5679.         $url    $schema $_SERVER['HTTP_HOST'] . $path;
  5680.     }
  5681.     return rtrim$url'/' );
  5682. }
  5683. /**
  5684.  * Temporarily suspends cache additions.
  5685.  *
  5686.  * Stops more data being added to the cache, but still allows cache retrieval.
  5687.  * This is useful for actions, such as imports, when a lot of data would otherwise
  5688.  * be almost uselessly added to the cache.
  5689.  *
  5690.  * Suspension lasts for a single page load at most. Remember to call this
  5691.  * function again if you wish to re-enable cache adds earlier.
  5692.  *
  5693.  * @since 3.3.0
  5694.  *
  5695.  * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
  5696.  *                      Defaults to not changing the current setting.
  5697.  * @return bool The current suspend setting.
  5698.  */
  5699. function wp_suspend_cache_addition$suspend null ) {
  5700.     static $_suspend false;
  5701.     if ( is_bool$suspend ) ) {
  5702.         $_suspend $suspend;
  5703.     }
  5704.     return $_suspend;
  5705. }
  5706. /**
  5707.  * Suspends cache invalidation.
  5708.  *
  5709.  * Turns cache invalidation on and off. Useful during imports where you don't want to do
  5710.  * invalidations every time a post is inserted. Callers must be sure that what they are
  5711.  * doing won't lead to an inconsistent cache when invalidation is suspended.
  5712.  *
  5713.  * @since 2.7.0
  5714.  *
  5715.  * @global bool $_wp_suspend_cache_invalidation
  5716.  *
  5717.  * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
  5718.  * @return bool The current suspend setting.
  5719.  */
  5720. function wp_suspend_cache_invalidation$suspend true ) {
  5721.     global $_wp_suspend_cache_invalidation;
  5722.     $current_suspend                $_wp_suspend_cache_invalidation;
  5723.     $_wp_suspend_cache_invalidation $suspend;
  5724.     return $current_suspend;
  5725. }
  5726. /**
  5727.  * Determines whether a site is the main site of the current network.
  5728.  *
  5729.  * @since 3.0.0
  5730.  * @since 4.9.0 The `$network_id` parameter was added.
  5731.  *
  5732.  * @param int $site_id    Optional. Site ID to test. Defaults to current site.
  5733.  * @param int $network_id Optional. Network ID of the network to check for.
  5734.  *                        Defaults to current network.
  5735.  * @return bool True if $site_id is the main site of the network, or if not
  5736.  *              running Multisite.
  5737.  */
  5738. function is_main_site$site_id null$network_id null ) {
  5739.     if ( ! is_multisite() ) {
  5740.         return true;
  5741.     }
  5742.     if ( ! $site_id ) {
  5743.         $site_id get_current_blog_id();
  5744.     }
  5745.     $site_id = (int) $site_id;
  5746.     return get_main_site_id$network_id ) === $site_id;
  5747. }
  5748. /**
  5749.  * Gets the main site ID.
  5750.  *
  5751.  * @since 4.9.0
  5752.  *
  5753.  * @param int $network_id Optional. The ID of the network for which to get the main site.
  5754.  *                        Defaults to the current network.
  5755.  * @return int The ID of the main site.
  5756.  */
  5757. function get_main_site_id$network_id null ) {
  5758.     if ( ! is_multisite() ) {
  5759.         return get_current_blog_id();
  5760.     }
  5761.     $network get_network$network_id );
  5762.     if ( ! $network ) {
  5763.         return 0;
  5764.     }
  5765.     return $network->site_id;
  5766. }
  5767. /**
  5768.  * Determines whether a network is the main network of the Multisite installation.
  5769.  *
  5770.  * @since 3.7.0
  5771.  *
  5772.  * @param int $network_id Optional. Network ID to test. Defaults to current network.
  5773.  * @return bool True if $network_id is the main network, or if not running Multisite.
  5774.  */
  5775. function is_main_network$network_id null ) {
  5776.     if ( ! is_multisite() ) {
  5777.         return true;
  5778.     }
  5779.     if ( null === $network_id ) {
  5780.         $network_id get_current_network_id();
  5781.     }
  5782.     $network_id = (int) $network_id;
  5783.     return ( get_main_network_id() === $network_id );
  5784. }
  5785. /**
  5786.  * Gets the main network ID.
  5787.  *
  5788.  * @since 4.3.0
  5789.  *
  5790.  * @return int The ID of the main network.
  5791.  */
  5792. function get_main_network_id() {
  5793.     if ( ! is_multisite() ) {
  5794.         return 1;
  5795.     }
  5796.     $current_network get_network();
  5797.     if ( defined'PRIMARY_NETWORK_ID' ) ) {
  5798.         $main_network_id PRIMARY_NETWORK_ID;
  5799.     } elseif ( isset( $current_network->id ) && === (int) $current_network->id ) {
  5800.         // If the current network has an ID of 1, assume it is the main network.
  5801.         $main_network_id 1;
  5802.     } else {
  5803.         $_networks       get_networks(
  5804.             array(
  5805.                 'fields' => 'ids',
  5806.                 'number' => 1,
  5807.             )
  5808.         );
  5809.         $main_network_id array_shift$_networks );
  5810.     }
  5811.     /**
  5812.      * Filters the main network ID.
  5813.      *
  5814.      * @since 4.3.0
  5815.      *
  5816.      * @param int $main_network_id The ID of the main network.
  5817.      */
  5818.     return (int) apply_filters'get_main_network_id'$main_network_id );
  5819. }
  5820. /**
  5821.  * Determines whether site meta is enabled.
  5822.  *
  5823.  * This function checks whether the 'blogmeta' database table exists. The result is saved as
  5824.  * a setting for the main network, making it essentially a global setting. Subsequent requests
  5825.  * will refer to this setting instead of running the query.
  5826.  *
  5827.  * @since 5.1.0
  5828.  *
  5829.  * @global wpdb $wpdb WordPress database abstraction object.
  5830.  *
  5831.  * @return bool True if site meta is supported, false otherwise.
  5832.  */
  5833. function is_site_meta_supported() {
  5834.     global $wpdb;
  5835.     if ( ! is_multisite() ) {
  5836.         return false;
  5837.     }
  5838.     $network_id get_main_network_id();
  5839.     $supported get_network_option$network_id'site_meta_supported'false );
  5840.     if ( false === $supported ) {
  5841.         $supported $wpdb->get_var"SHOW TABLES LIKE '{$wpdb->blogmeta}'" ) ? 0;
  5842.         update_network_option$network_id'site_meta_supported'$supported );
  5843.     }
  5844.     return (bool) $supported;
  5845. }
  5846. /**
  5847.  * Modifies gmt_offset for smart timezone handling.
  5848.  *
  5849.  * Overrides the gmt_offset option if we have a timezone_string available.
  5850.  *
  5851.  * @since 2.8.0
  5852.  *
  5853.  * @return float|false Timezone GMT offset, false otherwise.
  5854.  */
  5855. function wp_timezone_override_offset() {
  5856.     $timezone_string get_option'timezone_string' );
  5857.     if ( ! $timezone_string ) {
  5858.         return false;
  5859.     }
  5860.     $timezone_object timezone_open$timezone_string );
  5861.     $datetime_object date_create();
  5862.     if ( false === $timezone_object || false === $datetime_object ) {
  5863.         return false;
  5864.     }
  5865.     return roundtimezone_offset_get$timezone_object$datetime_object ) / HOUR_IN_SECONDS);
  5866. }
  5867. /**
  5868.  * Sort-helper for timezones.
  5869.  *
  5870.  * @since 2.9.0
  5871.  * @access private
  5872.  *
  5873.  * @param array $a
  5874.  * @param array $b
  5875.  * @return int
  5876.  */
  5877. function _wp_timezone_choice_usort_callback$a$b ) {
  5878.     // Don't use translated versions of Etc.
  5879.     if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
  5880.         // Make the order of these more like the old dropdown.
  5881.         if ( str_starts_with$a['city'], 'GMT+' ) && str_starts_with$b['city'], 'GMT+' ) ) {
  5882.             return -* ( strnatcasecmp$a['city'], $b['city'] ) );
  5883.         }
  5884.         if ( 'UTC' === $a['city'] ) {
  5885.             if ( str_starts_with$b['city'], 'GMT+' ) ) {
  5886.                 return 1;
  5887.             }
  5888.             return -1;
  5889.         }
  5890.         if ( 'UTC' === $b['city'] ) {
  5891.             if ( str_starts_with$a['city'], 'GMT+' ) ) {
  5892.                 return -1;
  5893.             }
  5894.             return 1;
  5895.         }
  5896.         return strnatcasecmp$a['city'], $b['city'] );
  5897.     }
  5898.     if ( $a['t_continent'] === $b['t_continent'] ) {
  5899.         if ( $a['t_city'] === $b['t_city'] ) {
  5900.             return strnatcasecmp$a['t_subcity'], $b['t_subcity'] );
  5901.         }
  5902.         return strnatcasecmp$a['t_city'], $b['t_city'] );
  5903.     } else {
  5904.         // Force Etc to the bottom of the list.
  5905.         if ( 'Etc' === $a['continent'] ) {
  5906.             return 1;
  5907.         }
  5908.         if ( 'Etc' === $b['continent'] ) {
  5909.             return -1;
  5910.         }
  5911.         return strnatcasecmp$a['t_continent'], $b['t_continent'] );
  5912.     }
  5913. }
  5914. /**
  5915.  * Gives a nicely-formatted list of timezone strings.
  5916.  *
  5917.  * @since 2.9.0
  5918.  * @since 4.7.0 Added the `$locale` parameter.
  5919.  *
  5920.  * @param string $selected_zone Selected timezone.
  5921.  * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
  5922.  * @return string
  5923.  */
  5924. function wp_timezone_choice$selected_zone$locale null ) {
  5925.     static $mo_loaded false$locale_loaded null;
  5926.     $continents = array( 'Africa''America''Antarctica''Arctic''Asia''Atlantic''Australia''Europe''Indian''Pacific' );
  5927.     // Load translations for continents and cities.
  5928.     if ( ! $mo_loaded || $locale !== $locale_loaded ) {
  5929.         $locale_loaded $locale $locale get_locale();
  5930.         $mofile        WP_LANG_DIR '/continents-cities-' $locale_loaded '.mo';
  5931.         unload_textdomain'continents-cities'true );
  5932.         load_textdomain'continents-cities'$mofile$locale_loaded );
  5933.         $mo_loaded true;
  5934.     }
  5935.     $tz_identifiers timezone_identifiers_list();
  5936.     $zonen          = array();
  5937.     foreach ( $tz_identifiers as $zone ) {
  5938.         $zone explode'/'$zone );
  5939.         if ( ! in_array$zone[0], $continentstrue ) ) {
  5940.             continue;
  5941.         }
  5942.         // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later.
  5943.         $exists    = array(
  5944.             => ( isset( $zone[0] ) && $zone[0] ),
  5945.             => ( isset( $zone[1] ) && $zone[1] ),
  5946.             => ( isset( $zone[2] ) && $zone[2] ),
  5947.         );
  5948.         $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
  5949.         $exists[4] = ( $exists[1] && $exists[3] );
  5950.         $exists[5] = ( $exists[2] && $exists[3] );
  5951.         // phpcs:disable WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText
  5952.         $zonen[] = array(
  5953.             'continent'   => ( $exists[0] ? $zone[0] : '' ),
  5954.             'city'        => ( $exists[1] ? $zone[1] : '' ),
  5955.             'subcity'     => ( $exists[2] ? $zone[2] : '' ),
  5956.             't_continent' => ( $exists[3] ? translatestr_replace'_'' '$zone[0] ), 'continents-cities' ) : '' ),
  5957.             't_city'      => ( $exists[4] ? translatestr_replace'_'' '$zone[1] ), 'continents-cities' ) : '' ),
  5958.             't_subcity'   => ( $exists[5] ? translatestr_replace'_'' '$zone[2] ), 'continents-cities' ) : '' ),
  5959.         );
  5960.         // phpcs:enable
  5961.     }
  5962.     usort$zonen'_wp_timezone_choice_usort_callback' );
  5963.     $structure = array();
  5964.     if ( empty( $selected_zone ) ) {
  5965.         $structure[] = '<option selected="selected" value="">' __'Select a city' ) . '</option>';
  5966.     }
  5967.     // If this is a deprecated, but valid, timezone string, display it at the top of the list as-is.
  5968.     if ( in_array$selected_zone$tz_identifierstrue ) === false
  5969.         && in_array$selected_zonetimezone_identifiers_listDateTimeZone::ALL_WITH_BC ), true )
  5970.     ) {
  5971.         $structure[] = '<option selected="selected" value="' esc_attr$selected_zone ) . '">' esc_html$selected_zone ) . '</option>';
  5972.     }
  5973.     foreach ( $zonen as $key => $zone ) {
  5974.         // Build value in an array to join later.
  5975.         $value = array( $zone['continent'] );
  5976.         if ( empty( $zone['city'] ) ) {
  5977.             // It's at the continent level (generally won't happen).
  5978.             $display $zone['t_continent'];
  5979.         } else {
  5980.             // It's inside a continent group.
  5981.             // Continent optgroup.
  5982.             if ( ! isset( $zonen$key ] ) || $zonen$key ]['continent'] !== $zone['continent'] ) {
  5983.                 $label       $zone['t_continent'];
  5984.                 $structure[] = '<optgroup label="' esc_attr$label ) . '">';
  5985.             }
  5986.             // Add the city to the value.
  5987.             $value[] = $zone['city'];
  5988.             $display $zone['t_city'];
  5989.             if ( ! empty( $zone['subcity'] ) ) {
  5990.                 // Add the subcity to the value.
  5991.                 $value[]  = $zone['subcity'];
  5992.                 $display .= ' - ' $zone['t_subcity'];
  5993.             }
  5994.         }
  5995.         // Build the value.
  5996.         $value    implode'/'$value );
  5997.         $selected '';
  5998.         if ( $value === $selected_zone ) {
  5999.             $selected 'selected="selected" ';
  6000.         }
  6001.         $structure[] = '<option ' $selected 'value="' esc_attr$value ) . '">' esc_html$display ) . '</option>';
  6002.         // Close continent optgroup.
  6003.         if ( ! empty( $zone['city'] ) && ( ! isset( $zonen$key ] ) || ( isset( $zonen$key ] ) && $zonen$key ]['continent'] !== $zone['continent'] ) ) ) {
  6004.             $structure[] = '</optgroup>';
  6005.         }
  6006.     }
  6007.     // Do UTC.
  6008.     $structure[] = '<optgroup label="' esc_attr__'UTC' ) . '">';
  6009.     $selected    '';
  6010.     if ( 'UTC' === $selected_zone ) {
  6011.         $selected 'selected="selected" ';
  6012.     }
  6013.     $structure[] = '<option ' $selected 'value="' esc_attr'UTC' ) . '">' __'UTC' ) . '</option>';
  6014.     $structure[] = '</optgroup>';
  6015.     // Do manual UTC offsets.
  6016.     $structure[]  = '<optgroup label="' esc_attr__'Manual Offsets' ) . '">';
  6017.     $offset_range = array(
  6018.         -12,
  6019.         -11.5,
  6020.         -11,
  6021.         -10.5,
  6022.         -10,
  6023.         -9.5,
  6024.         -9,
  6025.         -8.5,
  6026.         -8,
  6027.         -7.5,
  6028.         -7,
  6029.         -6.5,
  6030.         -6,
  6031.         -5.5,
  6032.         -5,
  6033.         -4.5,
  6034.         -4,
  6035.         -3.5,
  6036.         -3,
  6037.         -2.5,
  6038.         -2,
  6039.         -1.5,
  6040.         -1,
  6041.         -0.5,
  6042.         0,
  6043.         0.5,
  6044.         1,
  6045.         1.5,
  6046.         2,
  6047.         2.5,
  6048.         3,
  6049.         3.5,
  6050.         4,
  6051.         4.5,
  6052.         5,
  6053.         5.5,
  6054.         5.75,
  6055.         6,
  6056.         6.5,
  6057.         7,
  6058.         7.5,
  6059.         8,
  6060.         8.5,
  6061.         8.75,
  6062.         9,
  6063.         9.5,
  6064.         10,
  6065.         10.5,
  6066.         11,
  6067.         11.5,
  6068.         12,
  6069.         12.75,
  6070.         13,
  6071.         13.75,
  6072.         14,
  6073.     );
  6074.     foreach ( $offset_range as $offset ) {
  6075.         if ( <= $offset ) {
  6076.             $offset_name '+' $offset;
  6077.         } else {
  6078.             $offset_name = (string) $offset;
  6079.         }
  6080.         $offset_value $offset_name;
  6081.         $offset_name  str_replace( array( '.25''.5''.75' ), array( ':15'':30'':45' ), $offset_name );
  6082.         $offset_name  'UTC' $offset_name;
  6083.         $offset_value 'UTC' $offset_value;
  6084.         $selected     '';
  6085.         if ( $offset_value === $selected_zone ) {
  6086.             $selected 'selected="selected" ';
  6087.         }
  6088.         $structure[] = '<option ' $selected 'value="' esc_attr$offset_value ) . '">' esc_html$offset_name ) . '</option>';
  6089.     }
  6090.     $structure[] = '</optgroup>';
  6091.     return implode"\n"$structure );
  6092. }
  6093. /**
  6094.  * Strips close comment and close php tags from file headers used by WP.
  6095.  *
  6096.  * @since 2.8.0
  6097.  * @access private
  6098.  *
  6099.  * @see https://core.trac.wordpress.org/ticket/8497
  6100.  *
  6101.  * @param string $str Header comment to clean up.
  6102.  * @return string
  6103.  */
  6104. function _cleanup_header_comment$str ) {
  6105.     return trimpreg_replace'/\s*(?:\*\/|\?>).*/'''$str ) );
  6106. }
  6107. /**
  6108.  * Permanently deletes comments or posts of any type that have held a status
  6109.  * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
  6110.  *
  6111.  * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
  6112.  *
  6113.  * @since 2.9.0
  6114.  *
  6115.  * @global wpdb $wpdb WordPress database abstraction object.
  6116.  */
  6117. function wp_scheduled_delete() {
  6118.     global $wpdb;
  6119.     $delete_timestamp time() - ( DAY_IN_SECONDS EMPTY_TRASH_DAYS );
  6120.     $posts_to_delete $wpdb->get_results$wpdb->prepare"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d"$delete_timestamp ), ARRAY_A );
  6121.     foreach ( (array) $posts_to_delete as $post ) {
  6122.         $post_id = (int) $post['post_id'];
  6123.         if ( ! $post_id ) {
  6124.             continue;
  6125.         }
  6126.         $del_post get_post$post_id );
  6127.         if ( ! $del_post || 'trash' !== $del_post->post_status ) {
  6128.             delete_post_meta$post_id'_wp_trash_meta_status' );
  6129.             delete_post_meta$post_id'_wp_trash_meta_time' );
  6130.         } else {
  6131.             wp_delete_post$post_id );
  6132.         }
  6133.     }
  6134.     $comments_to_delete $wpdb->get_results$wpdb->prepare"SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < %d"$delete_timestamp ), ARRAY_A );
  6135.     foreach ( (array) $comments_to_delete as $comment ) {
  6136.         $comment_id = (int) $comment['comment_id'];
  6137.         if ( ! $comment_id ) {
  6138.             continue;
  6139.         }
  6140.         $del_comment get_comment$comment_id );
  6141.         if ( ! $del_comment || 'trash' !== $del_comment->comment_approved ) {
  6142.             delete_comment_meta$comment_id'_wp_trash_meta_time' );
  6143.             delete_comment_meta$comment_id'_wp_trash_meta_status' );
  6144.         } else {
  6145.             wp_delete_comment$del_comment );
  6146.         }
  6147.     }
  6148. }
  6149. /**
  6150.  * Retrieves metadata from a file.
  6151.  *
  6152.  * Searches for metadata in the first 8 KB of a file, such as a plugin or theme.
  6153.  * Each piece of metadata must be on its own line. Fields can not span multiple
  6154.  * lines, the value will get cut at the end of the first line.
  6155.  *
  6156.  * If the file data is not within that first 8 KB, then the author should correct
  6157.  * their plugin file and move the data headers to the top.
  6158.  *
  6159.  * @link https://codex.wordpress.org/File_Header
  6160.  *
  6161.  * @since 2.9.0
  6162.  *
  6163.  * @param string $file            Absolute path to the file.
  6164.  * @param array  $default_headers List of headers, in the format `array( 'HeaderKey' => 'Header Name' )`.
  6165.  * @param string $context         Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
  6166.  *                                Default empty string.
  6167.  * @return string[] Array of file header values keyed by header name.
  6168.  */
  6169. function get_file_data$file$default_headers$context '' ) {
  6170.     // Pull only the first 8 KB of the file in.
  6171.     $file_data file_get_contents$filefalsenull0KB_IN_BYTES );
  6172.     if ( false === $file_data ) {
  6173.         $file_data '';
  6174.     }
  6175.     // Make sure we catch CR-only line endings.
  6176.     $file_data str_replace"\r""\n"$file_data );
  6177.     /**
  6178.      * Filters extra file headers by context.
  6179.      *
  6180.      * The dynamic portion of the hook name, `$context`, refers to
  6181.      * the context where extra headers might be loaded.
  6182.      *
  6183.      * @since 2.9.0
  6184.      *
  6185.      * @param array $extra_context_headers Empty array by default.
  6186.      */
  6187.     $extra_headers $context apply_filters"extra_{$context}_headers", array() ) : array();
  6188.     if ( $extra_headers ) {
  6189.         $extra_headers array_combine$extra_headers$extra_headers ); // Keys equal values.
  6190.         $all_headers   array_merge$extra_headers, (array) $default_headers );
  6191.     } else {
  6192.         $all_headers $default_headers;
  6193.     }
  6194.     foreach ( $all_headers as $field => $regex ) {
  6195.         if ( preg_match'/^(?:[ \t]*<\?php)?[ \t\/*#@]*' preg_quote$regex'/' ) . ':(.*)$/mi'$file_data$match ) && $match[1] ) {
  6196.             $all_headers$field ] = _cleanup_header_comment$match[1] );
  6197.         } else {
  6198.             $all_headers$field ] = '';
  6199.         }
  6200.     }
  6201.     return $all_headers;
  6202. }
  6203. /**
  6204.  * Returns true.
  6205.  *
  6206.  * Useful for returning true to filters easily.
  6207.  *
  6208.  * @since 3.0.0
  6209.  *
  6210.  * @see __return_false()
  6211.  *
  6212.  * @return true True.
  6213.  */
  6214. function __return_true() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6215.     return true;
  6216. }
  6217. /**
  6218.  * Returns false.
  6219.  *
  6220.  * Useful for returning false to filters easily.
  6221.  *
  6222.  * @since 3.0.0
  6223.  *
  6224.  * @see __return_true()
  6225.  *
  6226.  * @return false False.
  6227.  */
  6228. function __return_false() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6229.     return false;
  6230. }
  6231. /**
  6232.  * Returns 0.
  6233.  *
  6234.  * Useful for returning 0 to filters easily.
  6235.  *
  6236.  * @since 3.0.0
  6237.  *
  6238.  * @return int 0.
  6239.  */
  6240. function __return_zero() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6241.     return 0;
  6242. }
  6243. /**
  6244.  * Returns an empty array.
  6245.  *
  6246.  * Useful for returning an empty array to filters easily.
  6247.  *
  6248.  * @since 3.0.0
  6249.  *
  6250.  * @return array Empty array.
  6251.  */
  6252. function __return_empty_array() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6253.     return array();
  6254. }
  6255. /**
  6256.  * Returns null.
  6257.  *
  6258.  * Useful for returning null to filters easily.
  6259.  *
  6260.  * @since 3.4.0
  6261.  *
  6262.  * @return null Null value.
  6263.  */
  6264. function __return_null() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6265.     return null;
  6266. }
  6267. /**
  6268.  * Returns an empty string.
  6269.  *
  6270.  * Useful for returning an empty string to filters easily.
  6271.  *
  6272.  * @since 3.7.0
  6273.  *
  6274.  * @see __return_null()
  6275.  *
  6276.  * @return string Empty string.
  6277.  */
  6278. function __return_empty_string() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
  6279.     return '';
  6280. }
  6281. /**
  6282.  * Sends a HTTP header to disable content type sniffing in browsers which support it.
  6283.  *
  6284.  * @since 3.0.0
  6285.  *
  6286.  * @see https://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
  6287.  * @see https://src.chromium.org/viewvc/chrome?view=rev&revision=6985
  6288.  */
  6289. function send_nosniff_header() {
  6290.     header'X-Content-Type-Options: nosniff' );
  6291. }
  6292. /**
  6293.  * Returns a MySQL expression for selecting the week number based on the start_of_week option.
  6294.  *
  6295.  * @ignore
  6296.  * @since 3.0.0
  6297.  *
  6298.  * @param string $column Database column.
  6299.  * @return string SQL clause.
  6300.  */
  6301. function _wp_mysql_week$column ) {
  6302.     $start_of_week = (int) get_option'start_of_week' );
  6303.     switch ( $start_of_week ) {
  6304.         case 1:
  6305.             return "WEEK( $column, 1 )";
  6306.         case 2:
  6307.         case 3:
  6308.         case 4:
  6309.         case 5:
  6310.         case 6:
  6311.             return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
  6312.         case 0:
  6313.         default:
  6314.             return "WEEK( $column, 0 )";
  6315.     }
  6316. }
  6317. /**
  6318.  * Finds hierarchy loops using a callback function that maps object IDs to parent IDs.
  6319.  *
  6320.  * @since 3.1.0
  6321.  * @access private
  6322.  *
  6323.  * @param callable $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
  6324.  * @param int      $start         The ID to start the loop check at.
  6325.  * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
  6326.  *                                Use null to always use $callback.
  6327.  * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
  6328.  * @return array IDs of all members of loop.
  6329.  */
  6330. function wp_find_hierarchy_loop$callback$start$start_parent$callback_args = array() ) {
  6331.     $override is_null$start_parent ) ? array() : array( $start => $start_parent );
  6332.     $arbitrary_loop_member wp_find_hierarchy_loop_tortoise_hare$callback$start$override$callback_args );
  6333.     if ( ! $arbitrary_loop_member ) {
  6334.         return array();
  6335.     }
  6336.     return wp_find_hierarchy_loop_tortoise_hare$callback$arbitrary_loop_member$override$callback_argstrue );
  6337. }
  6338. /**
  6339.  * Uses the "The Tortoise and the Hare" algorithm to detect loops.
  6340.  *
  6341.  * For every step of the algorithm, the hare takes two steps and the tortoise one.
  6342.  * If the hare ever laps the tortoise, there must be a loop.
  6343.  *
  6344.  * @since 3.1.0
  6345.  * @access private
  6346.  *
  6347.  * @param callable $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
  6348.  * @param int      $start         The ID to start the loop check at.
  6349.  * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
  6350.  *                                Default empty array.
  6351.  * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
  6352.  * @param bool     $_return_loop  Optional. Return loop members or just detect presence of loop? Only set
  6353.  *                                to true if you already know the given $start is part of a loop (otherwise
  6354.  *                                the returned array might include branches). Default false.
  6355.  * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
  6356.  *               $_return_loop
  6357.  */
  6358. function wp_find_hierarchy_loop_tortoise_hare$callback$start$override = array(), $callback_args = array(), $_return_loop false ) {
  6359.     $tortoise        $start;
  6360.     $hare            $start;
  6361.     $evanescent_hare $start;
  6362.     $return          = array();
  6363.     // Set evanescent_hare to one past hare. Increment hare two steps.
  6364.     while (
  6365.         $tortoise
  6366.     &&
  6367.         ( $evanescent_hare = isset( $override$hare ] ) ? $override$hare ] : call_user_func_array$callbackarray_merge( array( $hare ), $callback_args ) ) )
  6368.     &&
  6369.         ( $hare = isset( $override$evanescent_hare ] ) ? $override$evanescent_hare ] : call_user_func_array$callbackarray_merge( array( $evanescent_hare ), $callback_args ) ) )
  6370.     ) {
  6371.         if ( $_return_loop ) {
  6372.             $return$tortoise ]        = true;
  6373.             $return$evanescent_hare ] = true;
  6374.             $return$hare ]            = true;
  6375.         }
  6376.         // Tortoise got lapped - must be a loop.
  6377.         if ( $tortoise === $evanescent_hare || $tortoise === $hare ) {
  6378.             return $_return_loop $return $tortoise;
  6379.         }
  6380.         // Increment tortoise by one step.
  6381.         $tortoise = isset( $override$tortoise ] ) ? $override$tortoise ] : call_user_func_array$callbackarray_merge( array( $tortoise ), $callback_args ) );
  6382.     }
  6383.     return false;
  6384. }
  6385. /**
  6386.  * Sends a HTTP header to limit rendering of pages to same origin iframes.
  6387.  *
  6388.  * @since 3.1.3
  6389.  *
  6390.  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
  6391.  */
  6392. function send_frame_options_header() {
  6393.     header'X-Frame-Options: SAMEORIGIN' );
  6394. }
  6395. /**
  6396.  * Sends a referrer policy header so referrers are not sent externally from administration screens.
  6397.  *
  6398.  * @since 4.9.0
  6399.  * @since 6.8.0 This function was moved from `wp-admin/includes/misc.php` to `wp-includes/functions.php`.
  6400.  */
  6401. function wp_admin_headers() {
  6402.     $policy 'strict-origin-when-cross-origin';
  6403.     /**
  6404.      * Filters the admin referrer policy header value.
  6405.      *
  6406.      * @since 4.9.0
  6407.      * @since 4.9.5 The default value was changed to 'strict-origin-when-cross-origin'.
  6408.      *
  6409.      * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  6410.      *
  6411.      * @param string $policy The admin referrer policy header value. Default 'strict-origin-when-cross-origin'.
  6412.      */
  6413.     $policy apply_filters'admin_referrer_policy'$policy );
  6414.     headersprintf'Referrer-Policy: %s'$policy ) );
  6415. }
  6416. /**
  6417.  * Retrieves a list of protocols to allow in HTML attributes.
  6418.  *
  6419.  * @since 3.3.0
  6420.  * @since 4.3.0 Added 'webcal' to the protocols array.
  6421.  * @since 4.7.0 Added 'urn' to the protocols array.
  6422.  * @since 5.3.0 Added 'sms' to the protocols array.
  6423.  * @since 5.6.0 Added 'irc6' and 'ircs' to the protocols array.
  6424.  *
  6425.  * @see wp_kses()
  6426.  * @see esc_url()
  6427.  *
  6428.  * @return string[] Array of allowed protocols. Defaults to an array containing 'http', 'https',
  6429.  *                  'ftp', 'ftps', 'mailto', 'news', 'irc', 'irc6', 'ircs', 'gopher', 'nntp', 'feed',
  6430.  *                  'telnet', 'mms', 'rtsp', 'sms', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
  6431.  *                  This covers all common link protocols, except for 'javascript' which should not
  6432.  *                  be allowed for untrusted users.
  6433.  */
  6434. function wp_allowed_protocols() {
  6435.     static $protocols = array();
  6436.     if ( empty( $protocols ) ) {
  6437.         $protocols = array( 'http''https''ftp''ftps''mailto''news''irc''irc6''ircs''gopher''nntp''feed''telnet''mms''rtsp''sms''svn''tel''fax''xmpp''webcal''urn' );
  6438.     }
  6439.     if ( ! did_action'wp_loaded' ) ) {
  6440.         /**
  6441.          * Filters the list of protocols allowed in HTML attributes.
  6442.          *
  6443.          * @since 3.0.0
  6444.          *
  6445.          * @param string[] $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
  6446.          */
  6447.         $protocols array_unique( (array) apply_filters'kses_allowed_protocols'$protocols ) );
  6448.     }
  6449.     return $protocols;
  6450. }
  6451. /**
  6452.  * Returns a comma-separated string or array of functions that have been called to get
  6453.  * to the current point in code.
  6454.  *
  6455.  * @since 3.4.0
  6456.  *
  6457.  * @see https://core.trac.wordpress.org/ticket/19589
  6458.  *
  6459.  * @param string $ignore_class Optional. A class to ignore all function calls within - useful
  6460.  *                             when you want to just give info about the callee. Default null.
  6461.  * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
  6462.  *                             back to the source of the issue. Default 0.
  6463.  * @param bool   $pretty       Optional. Whether you want a comma separated string instead of
  6464.  *                             the raw array returned. Default true.
  6465.  * @return string|array Either a string containing a reversed comma separated trace or an array
  6466.  *                      of individual calls.
  6467.  */
  6468. function wp_debug_backtrace_summary$ignore_class null$skip_frames 0$pretty true ) {
  6469.     static $truncate_paths;
  6470.     $trace       debug_backtracefalse );
  6471.     $caller      = array();
  6472.     $check_class = ! is_null$ignore_class );
  6473.     ++$skip_frames// Skip this function.
  6474.     if ( ! isset( $truncate_paths ) ) {
  6475.         $truncate_paths = array(
  6476.             wp_normalize_pathWP_CONTENT_DIR ),
  6477.             wp_normalize_pathABSPATH ),
  6478.         );
  6479.     }
  6480.     foreach ( $trace as $call ) {
  6481.         if ( $skip_frames ) {
  6482.             --$skip_frames;
  6483.         } elseif ( isset( $call['class'] ) ) {
  6484.             if ( $check_class && $ignore_class === $call['class'] ) {
  6485.                 continue; // Filter out calls.
  6486.             }
  6487.             $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
  6488.         } else {
  6489.             if ( in_array$call['function'], array( 'do_action''apply_filters''do_action_ref_array''apply_filters_ref_array' ), true ) ) {
  6490.                 $caller[] = "{$call['function']}('{$call['args'][0]}')";
  6491.             } elseif ( in_array$call['function'], array( 'include''include_once''require''require_once' ), true ) ) {
  6492.                 $filename = isset( $call['args'][0] ) ? $call['args'][0] : '';
  6493.                 $caller[] = $call['function'] . "('" str_replace$truncate_paths''wp_normalize_path$filename ) ) . "')";
  6494.             } else {
  6495.                 $caller[] = $call['function'];
  6496.             }
  6497.         }
  6498.     }
  6499.     if ( $pretty ) {
  6500.         return implode', 'array_reverse$caller ) );
  6501.     } else {
  6502.         return $caller;
  6503.     }
  6504. }
  6505. /**
  6506.  * Retrieves IDs that are not already present in the cache.
  6507.  *
  6508.  * @since 3.4.0
  6509.  * @since 6.1.0 This function is no longer marked as "private".
  6510.  *
  6511.  * @param int[]  $object_ids  Array of IDs.
  6512.  * @param string $cache_group The cache group to check against.
  6513.  * @return int[] Array of IDs not present in the cache.
  6514.  */
  6515. function _get_non_cached_ids$object_ids$cache_group ) {
  6516.     $object_ids array_filter$object_ids'_validate_cache_id' );
  6517.     $object_ids array_uniquearray_map'intval'$object_ids ), SORT_NUMERIC );
  6518.     if ( empty( $object_ids ) ) {
  6519.         return array();
  6520.     }
  6521.     $non_cached_ids = array();
  6522.     $cache_values   wp_cache_get_multiple$object_ids$cache_group );
  6523.     foreach ( $cache_values as $id => $value ) {
  6524.         if ( false === $value ) {
  6525.             $non_cached_ids[] = (int) $id;
  6526.         }
  6527.     }
  6528.     return $non_cached_ids;
  6529. }
  6530. /**
  6531.  * Checks whether the given cache ID is either an integer or an integer-like string.
  6532.  *
  6533.  * Both `16` and `"16"` are considered valid, other numeric types and numeric strings
  6534.  * (`16.3` and `"16.3"`) are considered invalid.
  6535.  *
  6536.  * @since 6.3.0
  6537.  *
  6538.  * @param mixed $object_id The cache ID to validate.
  6539.  * @return bool Whether the given $object_id is a valid cache ID.
  6540.  */
  6541. function _validate_cache_id$object_id ) {
  6542.     /*
  6543.      * filter_var() could be used here, but the `filter` PHP extension
  6544.      * is considered optional and may not be available.
  6545.      */
  6546.     if ( is_int$object_id )
  6547.         || ( is_string$object_id ) && (string) (int) $object_id === $object_id ) ) {
  6548.         return true;
  6549.     }
  6550.     /* translators: %s: The type of the given object ID. */
  6551.     $message sprintf__'Object ID must be an integer, %s given.' ), gettype$object_id ) );
  6552.     _doing_it_wrong'_get_non_cached_ids'$message'6.3.0' );
  6553.     return false;
  6554. }
  6555. /**
  6556.  * Tests if the current device has the capability to upload files.
  6557.  *
  6558.  * @since 3.4.0
  6559.  * @access private
  6560.  *
  6561.  * @return bool Whether the device is able to upload files.
  6562.  */
  6563. function _device_can_upload() {
  6564.     if ( ! wp_is_mobile() ) {
  6565.         return true;
  6566.     }
  6567.     $ua $_SERVER['HTTP_USER_AGENT'];
  6568.     if ( str_contains$ua'iPhone' )
  6569.         || str_contains$ua'iPad' )
  6570.         || str_contains$ua'iPod' ) ) {
  6571.             return preg_match'#OS ([\d_]+) like Mac OS X#'$ua$version ) && version_compare$version[1], '6''>=' );
  6572.     }
  6573.     return true;
  6574. }
  6575. /**
  6576.  * Tests if a given path is a stream URL
  6577.  *
  6578.  * @since 3.5.0
  6579.  *
  6580.  * @param string $path The resource path or URL.
  6581.  * @return bool True if the path is a stream URL.
  6582.  */
  6583. function wp_is_stream$path ) {
  6584.     $scheme_separator strpos$path'://' );
  6585.     if ( false === $scheme_separator ) {
  6586.         // $path isn't a stream.
  6587.         return false;
  6588.     }
  6589.     $stream substr$path0$scheme_separator );
  6590.     return in_array$streamstream_get_wrappers(), true );
  6591. }
  6592. /**
  6593.  * Tests if the supplied date is valid for the Gregorian calendar.
  6594.  *
  6595.  * @since 3.5.0
  6596.  *
  6597.  * @link https://www.php.net/manual/en/function.checkdate.php
  6598.  *
  6599.  * @param int    $month       Month number.
  6600.  * @param int    $day         Day number.
  6601.  * @param int    $year        Year number.
  6602.  * @param string $source_date The date to filter.
  6603.  * @return bool True if valid date, false if not valid date.
  6604.  */
  6605. function wp_checkdate$month$day$year$source_date ) {
  6606.     /**
  6607.      * Filters whether the given date is valid for the Gregorian calendar.
  6608.      *
  6609.      * @since 3.5.0
  6610.      *
  6611.      * @param bool   $checkdate   Whether the given date is valid.
  6612.      * @param string $source_date Date to check.
  6613.      */
  6614.     return apply_filters'wp_checkdate'checkdate$month$day$year ), $source_date );
  6615. }
  6616. /**
  6617.  * Loads the auth check for monitoring whether the user is still logged in.
  6618.  *
  6619.  * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
  6620.  *
  6621.  * This is disabled for certain screens where a login screen could cause an
  6622.  * inconvenient interruption. A filter called {@see 'wp_auth_check_load'} can be used
  6623.  * for fine-grained control.
  6624.  *
  6625.  * @since 3.6.0
  6626.  */
  6627. function wp_auth_check_load() {
  6628.     if ( ! is_admin() && ! is_user_logged_in() ) {
  6629.         return;
  6630.     }
  6631.     if ( defined'IFRAME_REQUEST' ) ) {
  6632.         return;
  6633.     }
  6634.     $screen get_current_screen();
  6635.     $hidden = array( 'update''update-network''update-core''update-core-network''upgrade''upgrade-network''network' );
  6636.     $show   = ! in_array$screen->id$hiddentrue );
  6637.     /**
  6638.      * Filters whether to load the authentication check.
  6639.      *
  6640.      * Returning a falsey value from the filter will effectively short-circuit
  6641.      * loading the authentication check.
  6642.      *
  6643.      * @since 3.6.0
  6644.      *
  6645.      * @param bool      $show   Whether to load the authentication check.
  6646.      * @param WP_Screen $screen The current screen object.
  6647.      */
  6648.     if ( apply_filters'wp_auth_check_load'$show$screen ) ) {
  6649.         wp_enqueue_style'wp-auth-check' );
  6650.         wp_enqueue_script'wp-auth-check' );
  6651.         add_action'admin_print_footer_scripts''wp_auth_check_html');
  6652.         add_action'wp_print_footer_scripts''wp_auth_check_html');
  6653.     }
  6654. }
  6655. /**
  6656.  * Outputs the HTML that shows the wp-login dialog when the user is no longer logged in.
  6657.  *
  6658.  * @since 3.6.0
  6659.  */
  6660. function wp_auth_check_html() {
  6661.     $login_url      wp_login_url();
  6662.     $current_domain = ( is_ssl() ? 'https://' 'http://' ) . $_SERVER['HTTP_HOST'];
  6663.     $same_domain    str_starts_with$login_url$current_domain );
  6664.     /**
  6665.      * Filters whether the authentication check originated at the same domain.
  6666.      *
  6667.      * @since 3.6.0
  6668.      *
  6669.      * @param bool $same_domain Whether the authentication check originated at the same domain.
  6670.      */
  6671.     $same_domain apply_filters'wp_auth_check_same_domain'$same_domain );
  6672.     $wrap_class  $same_domain 'hidden' 'hidden fallback';
  6673.     ?>
  6674.     <div id="wp-auth-check-wrap" class="<?php echo $wrap_class?>">
  6675.     <div id="wp-auth-check-bg"></div>
  6676.     <div id="wp-auth-check">
  6677.     <button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text">
  6678.         <?php
  6679.         /* translators: Hidden accessibility text. */
  6680.         _e'Close dialog' );
  6681.         ?>
  6682.     </span></button>
  6683.     <?php
  6684.     if ( $same_domain ) {
  6685.         $login_src add_query_arg(
  6686.             array(
  6687.                 'interim-login' => '1',
  6688.                 'wp_lang'       => get_user_locale(),
  6689.             ),
  6690.             $login_url
  6691.         );
  6692.         ?>
  6693.         <div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url$login_src ); ?>"></div>
  6694.         <?php
  6695.     }
  6696.     ?>
  6697.     <div class="wp-auth-fallback">
  6698.         <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e'Session expired' ); ?></b></p>
  6699.         <p><a href="<?php echo esc_url$login_url ); ?>" target="_blank"><?php _e'Please log in again.' ); ?></a>
  6700.         <?php _e'The login page will open in a new tab. After logging in you can close it and return to this page.' ); ?></p>
  6701.     </div>
  6702.     </div>
  6703.     </div>
  6704.     <?php
  6705. }
  6706. /**
  6707.  * Checks whether a user is still logged in, for the heartbeat.
  6708.  *
  6709.  * Send a result that shows a log-in box if the user is no longer logged in,
  6710.  * or if their cookie is within the grace period.
  6711.  *
  6712.  * @since 3.6.0
  6713.  *
  6714.  * @global int $login_grace_period
  6715.  *
  6716.  * @param array $response  The Heartbeat response.
  6717.  * @return array The Heartbeat response with 'wp-auth-check' value set.
  6718.  */
  6719. function wp_auth_check$response ) {
  6720.     $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
  6721.     return $response;
  6722. }
  6723. /**
  6724.  * Returns RegEx body to liberally match an opening HTML tag.
  6725.  *
  6726.  * Matches an opening HTML tag that:
  6727.  * 1. Is self-closing or
  6728.  * 2. Has no body but has a closing tag of the same name or
  6729.  * 3. Contains a body and a closing tag of the same name
  6730.  *
  6731.  * Note: this RegEx does not balance inner tags and does not attempt
  6732.  * to produce valid HTML
  6733.  *
  6734.  * @since 3.6.0
  6735.  *
  6736.  * @param string $tag An HTML tag name. Example: 'video'.
  6737.  * @return string Tag RegEx.
  6738.  */
  6739. function get_tag_regex$tag ) {
  6740.     if ( empty( $tag ) ) {
  6741.         return '';
  6742.     }
  6743.     return sprintf'<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)'tag_escape$tag ) );
  6744. }
  6745. /**
  6746.  * Indicates if a given slug for a character set represents the UTF-8
  6747.  * text encoding. If not provided, examines the current blog's charset.
  6748.  *
  6749.  * A charset is considered to represent UTF-8 if it is a case-insensitive
  6750.  * match of "UTF-8" with or without the hyphen.
  6751.  *
  6752.  * Example:
  6753.  *
  6754.  *     true  === is_utf8_charset( 'UTF-8' );
  6755.  *     true  === is_utf8_charset( 'utf8' );
  6756.  *     false === is_utf8_charset( 'latin1' );
  6757.  *     false === is_utf8_charset( 'UTF 8' );
  6758.  *
  6759.  *     // Only strings match.
  6760.  *     false === is_utf8_charset( [ 'charset' => 'utf-8' ] );
  6761.  *
  6762.  *     // Without a given charset, it depends on the site option "blog_charset".
  6763.  *     $is_utf8 = is_utf8_charset();
  6764.  *
  6765.  * @since 6.6.0
  6766.  * @since 6.6.1 A wrapper for _is_utf8_charset
  6767.  *
  6768.  * @see _is_utf8_charset
  6769.  *
  6770.  * @param string|null $blog_charset Optional. Slug representing a text character encoding, or "charset".
  6771.  *                                  E.g. "UTF-8", "Windows-1252", "ISO-8859-1", "SJIS".
  6772.  *                                  Default value is to infer from "blog_charset" option.
  6773.  * @return bool Whether the slug represents the UTF-8 encoding.
  6774.  */
  6775. function is_utf8_charset$blog_charset null ) {
  6776.     return _is_utf8_charset$blog_charset ?? get_option'blog_charset' ) );
  6777. }
  6778. /**
  6779.  * Retrieves a canonical form of the provided charset appropriate for passing to PHP
  6780.  * functions such as htmlspecialchars() and charset HTML attributes.
  6781.  *
  6782.  * @since 3.6.0
  6783.  * @access private
  6784.  *
  6785.  * @see https://core.trac.wordpress.org/ticket/23688
  6786.  *
  6787.  * @param string $charset A charset name, e.g. "UTF-8", "Windows-1252", "SJIS".
  6788.  * @return string The canonical form of the charset.
  6789.  */
  6790. function _canonical_charset$charset ) {
  6791.     if ( is_utf8_charset$charset ) ) {
  6792.         return 'UTF-8';
  6793.     }
  6794.     /*
  6795.      * Normalize the ISO-8859-1 family of languages.
  6796.      *
  6797.      * This is not required for htmlspecialchars(), as it properly recognizes all of
  6798.      * the input character sets that here are transformed into "ISO-8859-1".
  6799.      *
  6800.      * @todo Should this entire check be removed since it's not required for the stated purpose?
  6801.      * @todo Should WordPress transform other potential charset equivalents, such as "latin1"?
  6802.      */
  6803.     if (
  6804.         ( === strcasecmp'iso-8859-1'$charset ) ) ||
  6805.         ( === strcasecmp'iso8859-1'$charset ) )
  6806.     ) {
  6807.         return 'ISO-8859-1';
  6808.     }
  6809.     return $charset;
  6810. }
  6811. /**
  6812.  * Sets the mbstring internal encoding to a binary safe encoding when func_overload
  6813.  * is enabled.
  6814.  *
  6815.  * When mbstring.func_overload is in use for multi-byte encodings, the results from
  6816.  * strlen() and similar functions respect the utf8 characters, causing binary data
  6817.  * to return incorrect lengths.
  6818.  *
  6819.  * This function overrides the mbstring encoding to a binary-safe encoding, and
  6820.  * resets it to the users expected encoding afterwards through the
  6821.  * `reset_mbstring_encoding` function.
  6822.  *
  6823.  * It is safe to recursively call this function, however each
  6824.  * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
  6825.  * of `reset_mbstring_encoding()` calls.
  6826.  *
  6827.  * @since 3.7.0
  6828.  *
  6829.  * @see reset_mbstring_encoding()
  6830.  *
  6831.  * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
  6832.  *                    Default false.
  6833.  */
  6834. function mbstring_binary_safe_encoding$reset false ) {
  6835.     static $encodings  = array();
  6836.     static $overloaded null;
  6837.     if ( is_null$overloaded ) ) {
  6838.         if ( function_exists'mb_internal_encoding' )
  6839.             && ( (int) ini_get'mbstring.func_overload' ) & // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
  6840.         ) {
  6841.             $overloaded true;
  6842.         } else {
  6843.             $overloaded false;
  6844.         }
  6845.     }
  6846.     if ( false === $overloaded ) {
  6847.         return;
  6848.     }
  6849.     if ( ! $reset ) {
  6850.         $encoding mb_internal_encoding();
  6851.         array_push$encodings$encoding );
  6852.         mb_internal_encoding'ISO-8859-1' );
  6853.     }
  6854.     if ( $reset && $encodings ) {
  6855.         $encoding array_pop$encodings );
  6856.         mb_internal_encoding$encoding );
  6857.     }
  6858. }
  6859. /**
  6860.  * Resets the mbstring internal encoding to a users previously set encoding.
  6861.  *
  6862.  * @see mbstring_binary_safe_encoding()
  6863.  *
  6864.  * @since 3.7.0
  6865.  */
  6866. function reset_mbstring_encoding() {
  6867.     mbstring_binary_safe_encodingtrue );
  6868. }
  6869. /**
  6870.  * Filters/validates a variable as a boolean.
  6871.  *
  6872.  * Alternative to `filter_var( $value, FILTER_VALIDATE_BOOLEAN )`.
  6873.  *
  6874.  * @since 4.0.0
  6875.  *
  6876.  * @param mixed $value Boolean value to validate.
  6877.  * @return bool Whether the value is validated.
  6878.  */
  6879. function wp_validate_boolean$value ) {
  6880.     if ( is_bool$value ) ) {
  6881.         return $value;
  6882.     }
  6883.     if ( is_string$value ) && 'false' === strtolower$value ) ) {
  6884.         return false;
  6885.     }
  6886.     return (bool) $value;
  6887. }
  6888. /**
  6889.  * Deletes a file.
  6890.  *
  6891.  * @since 4.2.0
  6892.  * @since 6.7.0 A return value was added.
  6893.  *
  6894.  * @param string $file The path to the file to delete.
  6895.  * @return bool True on success, false on failure.
  6896.  */
  6897. function wp_delete_file$file ) {
  6898.     /**
  6899.      * Filters the path of the file to delete.
  6900.      *
  6901.      * @since 2.1.0
  6902.      *
  6903.      * @param string $file Path to the file to delete.
  6904.      */
  6905.     $delete apply_filters'wp_delete_file'$file );
  6906.     if ( ! empty( $delete ) ) {
  6907.         return @unlink$delete );
  6908.     }
  6909.     return false;
  6910. }
  6911. /**
  6912.  * Deletes a file if its path is within the given directory.
  6913.  *
  6914.  * @since 4.9.7
  6915.  *
  6916.  * @param string $file      Absolute path to the file to delete.
  6917.  * @param string $directory Absolute path to a directory.
  6918.  * @return bool True on success, false on failure.
  6919.  */
  6920. function wp_delete_file_from_directory$file$directory ) {
  6921.     if ( wp_is_stream$file ) ) {
  6922.         $real_file      $file;
  6923.         $real_directory $directory;
  6924.     } else {
  6925.         $real_file      realpathwp_normalize_path$file ) );
  6926.         $real_directory realpathwp_normalize_path$directory ) );
  6927.     }
  6928.     if ( false !== $real_file ) {
  6929.         $real_file wp_normalize_path$real_file );
  6930.     }
  6931.     if ( false !== $real_directory ) {
  6932.         $real_directory wp_normalize_path$real_directory );
  6933.     }
  6934.     if ( false === $real_file || false === $real_directory || ! str_starts_with$real_filetrailingslashit$real_directory ) ) ) {
  6935.         return false;
  6936.     }
  6937.     return wp_delete_file$file );
  6938. }
  6939. /**
  6940.  * Outputs a small JS snippet on preview tabs/windows to remove `window.name` when a user is navigating to another page.
  6941.  *
  6942.  * This prevents reusing the same tab for a preview when the user has navigated away.
  6943.  *
  6944.  * @since 4.3.0
  6945.  *
  6946.  * @global WP_Post $post Global post object.
  6947.  */
  6948. function wp_post_preview_js() {
  6949.     global $post;
  6950.     if ( ! is_preview() || empty( $post ) ) {
  6951.         return;
  6952.     }
  6953.     // Has to match the window name used in post_submit_meta_box().
  6954.     $name 'wp-preview-' . (int) $post->ID;
  6955.     ob_start();
  6956.     ?>
  6957.     <script>
  6958.     ( function() {
  6959.         var query = document.location.search;
  6960.         if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
  6961.             window.name = '<?php echo $name?>';
  6962.         }
  6963.         if ( window.addEventListener ) {
  6964.             window.addEventListener( 'pagehide', function() { window.name = ''; } );
  6965.         }
  6966.     }());
  6967.     </script>
  6968.     <?php
  6969.     wp_print_inline_script_tagwp_remove_surrounding_empty_script_tagsob_get_clean() ) );
  6970. }
  6971. /**
  6972.  * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601 (Y-m-d\TH:i:s).
  6973.  *
  6974.  * Explicitly strips timezones, as datetimes are not saved with any timezone
  6975.  * information. Including any information on the offset could be misleading.
  6976.  *
  6977.  * Despite historical function name, the output does not conform to RFC3339 format,
  6978.  * which must contain timezone.
  6979.  *
  6980.  * @since 4.4.0
  6981.  *
  6982.  * @param string $date_string Date string to parse and format.
  6983.  * @return string Date formatted for ISO8601 without time zone.
  6984.  */
  6985. function mysql_to_rfc3339$date_string ) {
  6986.     return mysql2date'Y-m-d\TH:i:s'$date_stringfalse );
  6987. }
  6988. /**
  6989.  * Attempts to raise the PHP memory limit for memory intensive processes.
  6990.  *
  6991.  * Only allows raising the existing limit and prevents lowering it.
  6992.  *
  6993.  * @since 4.6.0
  6994.  *
  6995.  * @param string $context Optional. Context in which the function is called. Accepts either 'admin',
  6996.  *                        'image', 'cron', or an arbitrary other context. If an arbitrary context is passed,
  6997.  *                        the similarly arbitrary {@see '$context_memory_limit'} filter will be
  6998.  *                        invoked. Default 'admin'.
  6999.  * @return int|string|false The limit that was set or false on failure.
  7000.  */
  7001. function wp_raise_memory_limit$context 'admin' ) {
  7002.     // Exit early if the limit cannot be changed.
  7003.     if ( false === wp_is_ini_value_changeable'memory_limit' ) ) {
  7004.         return false;
  7005.     }
  7006.     $current_limit     ini_get'memory_limit' );
  7007.     $current_limit_int wp_convert_hr_to_bytes$current_limit );
  7008.     if ( -=== $current_limit_int ) {
  7009.         return false;
  7010.     }
  7011.     $wp_max_limit     WP_MAX_MEMORY_LIMIT;
  7012.     $wp_max_limit_int wp_convert_hr_to_bytes$wp_max_limit );
  7013.     $filtered_limit   $wp_max_limit;
  7014.     switch ( $context ) {
  7015.         case 'admin':
  7016.             /**
  7017.              * Filters the maximum memory limit available for administration screens.
  7018.              *
  7019.              * This only applies to administrators, who may require more memory for tasks
  7020.              * like updates. Memory limits when processing images (uploaded or edited by
  7021.              * users of any role) are handled separately.
  7022.              *
  7023.              * The `WP_MAX_MEMORY_LIMIT` constant specifically defines the maximum memory
  7024.              * limit available when in the administration back end. The default is 256M
  7025.              * (256 megabytes of memory) or the original `memory_limit` php.ini value if
  7026.              * this is higher.
  7027.              *
  7028.              * @since 3.0.0
  7029.              * @since 4.6.0 The default now takes the original `memory_limit` into account.
  7030.              *
  7031.              * @param int|string $filtered_limit The maximum WordPress memory limit. Accepts an integer
  7032.              *                                   (bytes), or a shorthand string notation, such as '256M'.
  7033.              */
  7034.             $filtered_limit apply_filters'admin_memory_limit'$filtered_limit );
  7035.             break;
  7036.         case 'image':
  7037.             /**
  7038.              * Filters the memory limit allocated for image manipulation.
  7039.              *
  7040.              * @since 3.5.0
  7041.              * @since 4.6.0 The default now takes the original `memory_limit` into account.
  7042.              *
  7043.              * @param int|string $filtered_limit Maximum memory limit to allocate for image processing.
  7044.              *                                   Default `WP_MAX_MEMORY_LIMIT` or the original
  7045.              *                                   php.ini `memory_limit`, whichever is higher.
  7046.              *                                   Accepts an integer (bytes), or a shorthand string
  7047.              *                                   notation, such as '256M'.
  7048.              */
  7049.             $filtered_limit apply_filters'image_memory_limit'$filtered_limit );
  7050.             break;
  7051.         case 'cron':
  7052.             /**
  7053.              * Filters the memory limit allocated for WP-Cron event processing.
  7054.              *
  7055.              * @since 6.3.0
  7056.              *
  7057.              * @param int|string $filtered_limit Maximum memory limit to allocate for WP-Cron.
  7058.              *                                   Default `WP_MAX_MEMORY_LIMIT` or the original
  7059.              *                                   php.ini `memory_limit`, whichever is higher.
  7060.              *                                   Accepts an integer (bytes), or a shorthand string
  7061.              *                                   notation, such as '256M'.
  7062.              */
  7063.             $filtered_limit apply_filters'cron_memory_limit'$filtered_limit );
  7064.             break;
  7065.         default:
  7066.             /**
  7067.              * Filters the memory limit allocated for an arbitrary context.
  7068.              *
  7069.              * The dynamic portion of the hook name, `$context`, refers to an arbitrary
  7070.              * context passed on calling the function. This allows for plugins to define
  7071.              * their own contexts for raising the memory limit.
  7072.              *
  7073.              * @since 4.6.0
  7074.              *
  7075.              * @param int|string $filtered_limit Maximum memory limit to allocate for this context.
  7076.              *                                   Default WP_MAX_MEMORY_LIMIT` or the original php.ini `memory_limit`,
  7077.              *                                   whichever is higher. Accepts an integer (bytes), or a
  7078.              *                                   shorthand string notation, such as '256M'.
  7079.              */
  7080.             $filtered_limit apply_filters"{$context}_memory_limit"$filtered_limit );
  7081.             break;
  7082.     }
  7083.     $filtered_limit_int wp_convert_hr_to_bytes$filtered_limit );
  7084.     if ( -=== $filtered_limit_int || ( $filtered_limit_int $wp_max_limit_int && $filtered_limit_int $current_limit_int ) ) {
  7085.         if ( false !== ini_set'memory_limit'$filtered_limit ) ) {
  7086.             return $filtered_limit;
  7087.         } else {
  7088.             return false;
  7089.         }
  7090.     } elseif ( -=== $wp_max_limit_int || $wp_max_limit_int $current_limit_int ) {
  7091.         if ( false !== ini_set'memory_limit'$wp_max_limit ) ) {
  7092.             return $wp_max_limit;
  7093.         } else {
  7094.             return false;
  7095.         }
  7096.     }
  7097.     return false;
  7098. }
  7099. /**
  7100.  * Generates a random UUID (version 4).
  7101.  *
  7102.  * @since 4.7.0
  7103.  *
  7104.  * @return string UUID.
  7105.  */
  7106. function wp_generate_uuid4() {
  7107.     return sprintf(
  7108.         '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
  7109.         mt_rand00xffff ),
  7110.         mt_rand00xffff ),
  7111.         mt_rand00xffff ),
  7112.         mt_rand00x0fff ) | 0x4000,
  7113.         mt_rand00x3fff ) | 0x8000,
  7114.         mt_rand00xffff ),
  7115.         mt_rand00xffff ),
  7116.         mt_rand00xffff )
  7117.     );
  7118. }
  7119. /**
  7120.  * Validates that a UUID is valid.
  7121.  *
  7122.  * @since 4.9.0
  7123.  *
  7124.  * @param mixed $uuid    UUID to check.
  7125.  * @param int   $version Specify which version of UUID to check against. Default is none,
  7126.  *                       to accept any UUID version. Otherwise, only version allowed is `4`.
  7127.  * @return bool The string is a valid UUID or false on failure.
  7128.  */
  7129. function wp_is_uuid$uuid$version null ) {
  7130.     if ( ! is_string$uuid ) ) {
  7131.         return false;
  7132.     }
  7133.     if ( is_numeric$version ) ) {
  7134.         if ( !== (int) $version ) {
  7135.             _doing_it_wrong__FUNCTION____'Only UUID V4 is supported at this time.' ), '4.9.0' );
  7136.             return false;
  7137.         }
  7138.         $regex '/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/';
  7139.     } else {
  7140.         $regex '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/';
  7141.     }
  7142.     return (bool) preg_match$regex$uuid );
  7143. }
  7144. /**
  7145.  * Gets unique ID.
  7146.  *
  7147.  * This is a PHP implementation of Underscore's uniqueId method. A static variable
  7148.  * contains an integer that is incremented with each call. This number is returned
  7149.  * with the optional prefix. As such the returned value is not universally unique,
  7150.  * but it is unique across the life of the PHP process.
  7151.  *
  7152.  * @since 5.0.3
  7153.  *
  7154.  * @param string $prefix Prefix for the returned ID.
  7155.  * @return string Unique ID.
  7156.  */
  7157. function wp_unique_id$prefix '' ) {
  7158.     static $id_counter 0;
  7159.     return $prefix . (string) ++$id_counter;
  7160. }
  7161. /**
  7162.  * Generates an incremental ID that is independent per each different prefix.
  7163.  *
  7164.  * It is similar to `wp_unique_id`, but each prefix has its own internal ID
  7165.  * counter to make each prefix independent from each other. The ID starts at 1
  7166.  * and increments on each call. The returned value is not universally unique,
  7167.  * but it is unique across the life of the PHP process and it's stable per
  7168.  * prefix.
  7169.  *
  7170.  * @since 6.4.0
  7171.  *
  7172.  * @param string $prefix Optional. Prefix for the returned ID. Default empty string.
  7173.  * @return string Incremental ID per prefix.
  7174.  */
  7175. function wp_unique_prefixed_id$prefix '' ) {
  7176.     static $id_counters = array();
  7177.     if ( ! is_string$prefix ) ) {
  7178.         wp_trigger_error(
  7179.             __FUNCTION__,
  7180.             sprintf'The prefix must be a string. "%s" data type given.'gettype$prefix ) )
  7181.         );
  7182.         $prefix '';
  7183.     }
  7184.     if ( ! isset( $id_counters$prefix ] ) ) {
  7185.         $id_counters$prefix ] = 0;
  7186.     }
  7187.     $id = ++$id_counters$prefix ];
  7188.     return $prefix . (string) $id;
  7189. }
  7190. /**
  7191.  * Gets last changed date for the specified cache group.
  7192.  *
  7193.  * @since 4.7.0
  7194.  *
  7195.  * @param string $group Where the cache contents are grouped.
  7196.  * @return string UNIX timestamp with microseconds representing when the group was last changed.
  7197.  */
  7198. function wp_cache_get_last_changed$group ) {
  7199.     $last_changed wp_cache_get'last_changed'$group );
  7200.     if ( $last_changed ) {
  7201.         return $last_changed;
  7202.     }
  7203.     return wp_cache_set_last_changed$group );
  7204. }
  7205. /**
  7206.  * Sets last changed date for the specified cache group to now.
  7207.  *
  7208.  * @since 6.3.0
  7209.  *
  7210.  * @param string $group Where the cache contents are grouped.
  7211.  * @return string UNIX timestamp when the group was last changed.
  7212.  */
  7213. function wp_cache_set_last_changed$group ) {
  7214.     $previous_time wp_cache_get'last_changed'$group );
  7215.     $time microtime();
  7216.     wp_cache_set'last_changed'$time$group );
  7217.     /**
  7218.      * Fires after a cache group `last_changed` time is updated.
  7219.      * This may occur multiple times per page load and registered
  7220.      * actions must be performant.
  7221.      *
  7222.      * @since 6.3.0
  7223.      *
  7224.      * @param string       $group         The cache group name.
  7225.      * @param string       $time          The new last changed time (msec sec).
  7226.      * @param string|false $previous_time The previous last changed time. False if not previously set.
  7227.      */
  7228.     do_action'wp_cache_set_last_changed'$group$time$previous_time );
  7229.     return $time;
  7230. }
  7231. /**
  7232.  * Sends an email to the old site admin email address when the site admin email address changes.
  7233.  *
  7234.  * @since 4.9.0
  7235.  *
  7236.  * @param string $old_email   The old site admin email address.
  7237.  * @param string $new_email   The new site admin email address.
  7238.  * @param string $option_name The relevant database option name.
  7239.  */
  7240. function wp_site_admin_email_change_notification$old_email$new_email$option_name ) {
  7241.     $send true;
  7242.     // Don't send the notification to the default 'admin_email' value.
  7243.     if ( 'you@example.com' === $old_email ) {
  7244.         $send false;
  7245.     }
  7246.     /**
  7247.      * Filters whether to send the site admin email change notification email.
  7248.      *
  7249.      * @since 4.9.0
  7250.      *
  7251.      * @param bool   $send      Whether to send the email notification.
  7252.      * @param string $old_email The old site admin email address.
  7253.      * @param string $new_email The new site admin email address.
  7254.      */
  7255.     $send apply_filters'send_site_admin_email_change_email'$send$old_email$new_email );
  7256.     if ( ! $send ) {
  7257.         return;
  7258.     }
  7259.     /* translators: Do not translate OLD_EMAIL, NEW_EMAIL, SITENAME, SITEURL: those are placeholders. */
  7260.     $email_change_text __(
  7261.         'Hi,
  7262. This notice confirms that the admin email address was changed on ###SITENAME###.
  7263. The new admin email address is ###NEW_EMAIL###.
  7264. This email has been sent to ###OLD_EMAIL###
  7265. Regards,
  7266. All at ###SITENAME###
  7267. ###SITEURL###'
  7268.     );
  7269.     $email_change_email = array(
  7270.         'to'      => $old_email,
  7271.         /* translators: Site admin email change notification email subject. %s: Site title. */
  7272.         'subject' => __'[%s] Admin Email Changed' ),
  7273.         'message' => $email_change_text,
  7274.         'headers' => '',
  7275.     );
  7276.     // Get site name.
  7277.     $site_name wp_specialchars_decodeget_option'blogname' ), ENT_QUOTES );
  7278.     /**
  7279.      * Filters the contents of the email notification sent when the site admin email address is changed.
  7280.      *
  7281.      * @since 4.9.0
  7282.      *
  7283.      * @param array $email_change_email {
  7284.      *     Used to build wp_mail().
  7285.      *
  7286.      *     @type string $to      The intended recipient.
  7287.      *     @type string $subject The subject of the email.
  7288.      *     @type string $message The content of the email.
  7289.      *         The following strings have a special meaning and will get replaced dynamically:
  7290.      *         - ###OLD_EMAIL### The old site admin email address.
  7291.      *         - ###NEW_EMAIL### The new site admin email address.
  7292.      *         - ###SITENAME###  The name of the site.
  7293.      *         - ###SITEURL###   The URL to the site.
  7294.      *     @type string $headers Headers.
  7295.      * }
  7296.      * @param string $old_email The old site admin email address.
  7297.      * @param string $new_email The new site admin email address.
  7298.      */
  7299.     $email_change_email apply_filters'site_admin_email_change_email'$email_change_email$old_email$new_email );
  7300.     $email_change_email['message'] = str_replace'###OLD_EMAIL###'$old_email$email_change_email['message'] );
  7301.     $email_change_email['message'] = str_replace'###NEW_EMAIL###'$new_email$email_change_email['message'] );
  7302.     $email_change_email['message'] = str_replace'###SITENAME###'$site_name$email_change_email['message'] );
  7303.     $email_change_email['message'] = str_replace'###SITEURL###'home_url(), $email_change_email['message'] );
  7304.     wp_mail(
  7305.         $email_change_email['to'],
  7306.         sprintf(
  7307.             $email_change_email['subject'],
  7308.             $site_name
  7309.         ),
  7310.         $email_change_email['message'],
  7311.         $email_change_email['headers']
  7312.     );
  7313. }
  7314. /**
  7315.  * Returns an anonymized IPv4 or IPv6 address.
  7316.  *
  7317.  * @since 4.9.6 Abstracted from `WP_Community_Events::get_unsafe_client_ip()`.
  7318.  *
  7319.  * @param string $ip_addr       The IPv4 or IPv6 address to be anonymized.
  7320.  * @param bool   $ipv6_fallback Optional. Whether to return the original IPv6 address if the needed functions
  7321.  *                              to anonymize it are not present. Default false, return `::` (unspecified address).
  7322.  * @return string  The anonymized IP address.
  7323.  */
  7324. function wp_privacy_anonymize_ip$ip_addr$ipv6_fallback false ) {
  7325.     if ( empty( $ip_addr ) ) {
  7326.         return '0.0.0.0';
  7327.     }
  7328.     // Detect what kind of IP address this is.
  7329.     $ip_prefix '';
  7330.     $is_ipv6   substr_count$ip_addr':' ) > 1;
  7331.     $is_ipv4   = ( === substr_count$ip_addr'.' ) );
  7332.     if ( $is_ipv6 && $is_ipv4 ) {
  7333.         // IPv6 compatibility mode, temporarily strip the IPv6 part, and treat it like IPv4.
  7334.         $ip_prefix '::ffff:';
  7335.         $ip_addr   preg_replace'/^\[?[0-9a-f:]*:/i'''$ip_addr );
  7336.         $ip_addr   str_replace']'''$ip_addr );
  7337.         $is_ipv6   false;
  7338.     }
  7339.     if ( $is_ipv6 ) {
  7340.         // IPv6 addresses will always be enclosed in [] if there's a port.
  7341.         $left_bracket  strpos$ip_addr'[' );
  7342.         $right_bracket strpos$ip_addr']' );
  7343.         $percent       strpos$ip_addr'%' );
  7344.         $netmask       'ffff:ffff:ffff:ffff:0000:0000:0000:0000';
  7345.         // Strip the port (and [] from IPv6 addresses), if they exist.
  7346.         if ( false !== $left_bracket && false !== $right_bracket ) {
  7347.             $ip_addr substr$ip_addr$left_bracket 1$right_bracket $left_bracket );
  7348.         } elseif ( false !== $left_bracket || false !== $right_bracket ) {
  7349.             // The IP has one bracket, but not both, so it's malformed.
  7350.             return '::';
  7351.         }
  7352.         // Strip the reachability scope.
  7353.         if ( false !== $percent ) {
  7354.             $ip_addr substr$ip_addr0$percent );
  7355.         }
  7356.         // No invalid characters should be left.
  7357.         if ( preg_match'/[^0-9a-f:]/i'$ip_addr ) ) {
  7358.             return '::';
  7359.         }
  7360.         // Partially anonymize the IP by reducing it to the corresponding network ID.
  7361.         if ( function_exists'inet_pton' ) && function_exists'inet_ntop' ) ) {
  7362.             $ip_addr inet_ntopinet_pton$ip_addr ) & inet_pton$netmask ) );
  7363.             if ( false === $ip_addr ) {
  7364.                 return '::';
  7365.             }
  7366.         } elseif ( ! $ipv6_fallback ) {
  7367.             return '::';
  7368.         }
  7369.     } elseif ( $is_ipv4 ) {
  7370.         // Strip any port and partially anonymize the IP.
  7371.         $last_octet_position strrpos$ip_addr'.' );
  7372.         $ip_addr             substr$ip_addr0$last_octet_position ) . '.0';
  7373.     } else {
  7374.         return '0.0.0.0';
  7375.     }
  7376.     // Restore the IPv6 prefix to compatibility mode addresses.
  7377.     return $ip_prefix $ip_addr;
  7378. }
  7379. /**
  7380.  * Returns uniform "anonymous" data by type.
  7381.  *
  7382.  * @since 4.9.6
  7383.  *
  7384.  * @param string $type The type of data to be anonymized.
  7385.  * @param string $data Optional. The data to be anonymized. Default empty string.
  7386.  * @return string The anonymous data for the requested type.
  7387.  */
  7388. function wp_privacy_anonymize_data$type$data '' ) {
  7389.     switch ( $type ) {
  7390.         case 'email':
  7391.             $anonymous 'deleted@site.invalid';
  7392.             break;
  7393.         case 'url':
  7394.             $anonymous 'https://site.invalid';
  7395.             break;
  7396.         case 'ip':
  7397.             $anonymous wp_privacy_anonymize_ip$data );
  7398.             break;
  7399.         case 'date':
  7400.             $anonymous '0000-00-00 00:00:00';
  7401.             break;
  7402.         case 'text':
  7403.             /* translators: Deleted text. */
  7404.             $anonymous __'[deleted]' );
  7405.             break;
  7406.         case 'longtext':
  7407.             /* translators: Deleted long text. */
  7408.             $anonymous __'This content was deleted by the author.' );
  7409.             break;
  7410.         default:
  7411.             $anonymous '';
  7412.             break;
  7413.     }
  7414.     /**
  7415.      * Filters the anonymous data for each type.
  7416.      *
  7417.      * @since 4.9.6
  7418.      *
  7419.      * @param string $anonymous Anonymized data.
  7420.      * @param string $type      Type of the data.
  7421.      * @param string $data      Original data.
  7422.      */
  7423.     return apply_filters'wp_privacy_anonymize_data'$anonymous$type$data );
  7424. }
  7425. /**
  7426.  * Returns the directory used to store personal data export files.
  7427.  *
  7428.  * @since 4.9.6
  7429.  *
  7430.  * @see wp_privacy_exports_url
  7431.  *
  7432.  * @return string Exports directory.
  7433.  */
  7434. function wp_privacy_exports_dir() {
  7435.     $upload_dir  wp_upload_dir();
  7436.     $exports_dir trailingslashit$upload_dir['basedir'] ) . 'wp-personal-data-exports/';
  7437.     /**
  7438.      * Filters the directory used to store personal data export files.
  7439.      *
  7440.      * @since 4.9.6
  7441.      * @since 5.5.0 Exports now use relative paths, so changes to the directory
  7442.      *              via this filter should be reflected on the server.
  7443.      *
  7444.      * @param string $exports_dir Exports directory.
  7445.      */
  7446.     return apply_filters'wp_privacy_exports_dir'$exports_dir );
  7447. }
  7448. /**
  7449.  * Returns the URL of the directory used to store personal data export files.
  7450.  *
  7451.  * @since 4.9.6
  7452.  *
  7453.  * @see wp_privacy_exports_dir
  7454.  *
  7455.  * @return string Exports directory URL.
  7456.  */
  7457. function wp_privacy_exports_url() {
  7458.     $upload_dir  wp_upload_dir();
  7459.     $exports_url trailingslashit$upload_dir['baseurl'] ) . 'wp-personal-data-exports/';
  7460.     /**
  7461.      * Filters the URL of the directory used to store personal data export files.
  7462.      *
  7463.      * @since 4.9.6
  7464.      * @since 5.5.0 Exports now use relative paths, so changes to the directory URL
  7465.      *              via this filter should be reflected on the server.
  7466.      *
  7467.      * @param string $exports_url Exports directory URL.
  7468.      */
  7469.     return apply_filters'wp_privacy_exports_url'$exports_url );
  7470. }
  7471. /**
  7472.  * Schedules a `WP_Cron` job to delete expired export files.
  7473.  *
  7474.  * @since 4.9.6
  7475.  */
  7476. function wp_schedule_delete_old_privacy_export_files() {
  7477.     if ( wp_installing() ) {
  7478.         return;
  7479.     }
  7480.     if ( ! wp_next_scheduled'wp_privacy_delete_old_export_files' ) ) {
  7481.         wp_schedule_eventtime(), 'hourly''wp_privacy_delete_old_export_files' );
  7482.     }
  7483. }
  7484. /**
  7485.  * Cleans up export files older than three days old.
  7486.  *
  7487.  * The export files are stored in `wp-content/uploads`, and are therefore publicly
  7488.  * accessible. A CSPRN is appended to the filename to mitigate the risk of an
  7489.  * unauthorized person downloading the file, but it is still possible. Deleting
  7490.  * the file after the data subject has had a chance to delete it adds an additional
  7491.  * layer of protection.
  7492.  *
  7493.  * @since 4.9.6
  7494.  */
  7495. function wp_privacy_delete_old_export_files() {
  7496.     $exports_dir wp_privacy_exports_dir();
  7497.     if ( ! is_dir$exports_dir ) ) {
  7498.         return;
  7499.     }
  7500.     require_once ABSPATH 'wp-admin/includes/file.php';
  7501.     $export_files list_files$exports_dir100, array( 'index.php' ) );
  7502.     /**
  7503.      * Filters the lifetime, in seconds, of a personal data export file.
  7504.      *
  7505.      * By default, the lifetime is 3 days. Once the file reaches that age, it will automatically
  7506.      * be deleted by a cron job.
  7507.      *
  7508.      * @since 4.9.6
  7509.      *
  7510.      * @param int $expiration The expiration age of the export, in seconds.
  7511.      */
  7512.     $expiration apply_filters'wp_privacy_export_expiration'DAY_IN_SECONDS );
  7513.     foreach ( (array) $export_files as $export_file ) {
  7514.         $file_age_in_seconds time() - filemtime$export_file );
  7515.         if ( $expiration $file_age_in_seconds ) {
  7516.             unlink$export_file );
  7517.         }
  7518.     }
  7519. }
  7520. /**
  7521.  * Gets the URL to learn more about updating the PHP version the site is running on.
  7522.  *
  7523.  * This URL can be overridden by specifying an environment variable `WP_UPDATE_PHP_URL` or by using the
  7524.  * {@see 'wp_update_php_url'} filter. Providing an empty string is not allowed and will result in the
  7525.  * default URL being used. Furthermore the page the URL links to should preferably be localized in the
  7526.  * site language.
  7527.  *
  7528.  * @since 5.1.0
  7529.  *
  7530.  * @return string URL to learn more about updating PHP.
  7531.  */
  7532. function wp_get_update_php_url() {
  7533.     $default_url wp_get_default_update_php_url();
  7534.     $update_url $default_url;
  7535.     if ( false !== getenv'WP_UPDATE_PHP_URL' ) ) {
  7536.         $update_url getenv'WP_UPDATE_PHP_URL' );
  7537.     }
  7538.     /**
  7539.      * Filters the URL to learn more about updating the PHP version the site is running on.
  7540.      *
  7541.      * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
  7542.      * the page the URL links to should preferably be localized in the site language.
  7543.      *
  7544.      * @since 5.1.0
  7545.      *
  7546.      * @param string $update_url URL to learn more about updating PHP.
  7547.      */
  7548.     $update_url apply_filters'wp_update_php_url'$update_url );
  7549.     if ( empty( $update_url ) ) {
  7550.         $update_url $default_url;
  7551.     }
  7552.     return $update_url;
  7553. }
  7554. /**
  7555.  * Gets the default URL to learn more about updating the PHP version the site is running on.
  7556.  *
  7557.  * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_php_url()} when relying on the URL.
  7558.  * This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
  7559.  * default one.
  7560.  *
  7561.  * @since 5.1.0
  7562.  * @access private
  7563.  *
  7564.  * @return string Default URL to learn more about updating PHP.
  7565.  */
  7566. function wp_get_default_update_php_url() {
  7567.     return _x'https://wordpress.org/support/update-php/''localized PHP upgrade information page' );
  7568. }
  7569. /**
  7570.  * Prints the default annotation for the web host altering the "Update PHP" page URL.
  7571.  *
  7572.  * This function is to be used after {@see wp_get_update_php_url()} to display a consistent
  7573.  * annotation if the web host has altered the default "Update PHP" page URL.
  7574.  *
  7575.  * @since 5.1.0
  7576.  * @since 5.2.0 Added the `$before` and `$after` parameters.
  7577.  * @since 6.4.0 Added the `$display` parameter.
  7578.  *
  7579.  * @param string $before  Markup to output before the annotation. Default `<p class="description">`.
  7580.  * @param string $after   Markup to output after the annotation. Default `</p>`.
  7581.  * @param bool   $display Whether to echo or return the markup. Default `true` for echo.
  7582.  *
  7583.  * @return string|void
  7584.  */
  7585. function wp_update_php_annotation$before '<p class="description">'$after '</p>'$display true ) {
  7586.     $annotation wp_get_update_php_annotation();
  7587.     if ( $annotation ) {
  7588.         if ( $display ) {
  7589.             echo $before $annotation $after;
  7590.         } else {
  7591.             return $before $annotation $after;
  7592.         }
  7593.     }
  7594. }
  7595. /**
  7596.  * Returns the default annotation for the web hosting altering the "Update PHP" page URL.
  7597.  *
  7598.  * This function is to be used after {@see wp_get_update_php_url()} to return a consistent
  7599.  * annotation if the web host has altered the default "Update PHP" page URL.
  7600.  *
  7601.  * @since 5.2.0
  7602.  *
  7603.  * @return string Update PHP page annotation. An empty string if no custom URLs are provided.
  7604.  */
  7605. function wp_get_update_php_annotation() {
  7606.     $update_url  wp_get_update_php_url();
  7607.     $default_url wp_get_default_update_php_url();
  7608.     if ( $update_url === $default_url ) {
  7609.         return '';
  7610.     }
  7611.     $annotation sprintf(
  7612.         /* translators: %s: Default Update PHP page URL. */
  7613.         __'This resource is provided by your web host, and is specific to your site. For more information, <a href="%s" target="_blank">see the official WordPress documentation</a>.' ),
  7614.         esc_url$default_url )
  7615.     );
  7616.     return $annotation;
  7617. }
  7618. /**
  7619.  * Gets the URL for directly updating the PHP version the site is running on.
  7620.  *
  7621.  * A URL will only be returned if the `WP_DIRECT_UPDATE_PHP_URL` environment variable is specified or
  7622.  * by using the {@see 'wp_direct_php_update_url'} filter. This allows hosts to send users directly to
  7623.  * the page where they can update PHP to a newer version.
  7624.  *
  7625.  * @since 5.1.1
  7626.  *
  7627.  * @return string URL for directly updating PHP or empty string.
  7628.  */
  7629. function wp_get_direct_php_update_url() {
  7630.     $direct_update_url '';
  7631.     if ( false !== getenv'WP_DIRECT_UPDATE_PHP_URL' ) ) {
  7632.         $direct_update_url getenv'WP_DIRECT_UPDATE_PHP_URL' );
  7633.     }
  7634.     /**
  7635.      * Filters the URL for directly updating the PHP version the site is running on from the host.
  7636.      *
  7637.      * @since 5.1.1
  7638.      *
  7639.      * @param string $direct_update_url URL for directly updating PHP.
  7640.      */
  7641.     $direct_update_url apply_filters'wp_direct_php_update_url'$direct_update_url );
  7642.     return $direct_update_url;
  7643. }
  7644. /**
  7645.  * Displays a button directly linking to a PHP update process.
  7646.  *
  7647.  * This provides hosts with a way for users to be sent directly to their PHP update process.
  7648.  *
  7649.  * The button is only displayed if a URL is returned by `wp_get_direct_php_update_url()`.
  7650.  *
  7651.  * @since 5.1.1
  7652.  */
  7653. function wp_direct_php_update_button() {
  7654.     $direct_update_url wp_get_direct_php_update_url();
  7655.     if ( empty( $direct_update_url ) ) {
  7656.         return;
  7657.     }
  7658.     echo '<p class="button-container">';
  7659.     printf(
  7660.         '<a class="button button-primary" href="%1$s" target="_blank">%2$s<span class="screen-reader-text"> %3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
  7661.         esc_url$direct_update_url ),
  7662.         __'Update PHP' ),
  7663.         /* translators: Hidden accessibility text. */
  7664.         __'(opens in a new tab)' )
  7665.     );
  7666.     echo '</p>';
  7667. }
  7668. /**
  7669.  * Gets the URL to learn more about updating the site to use HTTPS.
  7670.  *
  7671.  * This URL can be overridden by specifying an environment variable `WP_UPDATE_HTTPS_URL` or by using the
  7672.  * {@see 'wp_update_https_url'} filter. Providing an empty string is not allowed and will result in the
  7673.  * default URL being used. Furthermore the page the URL links to should preferably be localized in the
  7674.  * site language.
  7675.  *
  7676.  * @since 5.7.0
  7677.  *
  7678.  * @return string URL to learn more about updating to HTTPS.
  7679.  */
  7680. function wp_get_update_https_url() {
  7681.     $default_url wp_get_default_update_https_url();
  7682.     $update_url $default_url;
  7683.     if ( false !== getenv'WP_UPDATE_HTTPS_URL' ) ) {
  7684.         $update_url getenv'WP_UPDATE_HTTPS_URL' );
  7685.     }
  7686.     /**
  7687.      * Filters the URL to learn more about updating the HTTPS version the site is running on.
  7688.      *
  7689.      * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
  7690.      * the page the URL links to should preferably be localized in the site language.
  7691.      *
  7692.      * @since 5.7.0
  7693.      *
  7694.      * @param string $update_url URL to learn more about updating HTTPS.
  7695.      */
  7696.     $update_url apply_filters'wp_update_https_url'$update_url );
  7697.     if ( empty( $update_url ) ) {
  7698.         $update_url $default_url;
  7699.     }
  7700.     return $update_url;
  7701. }
  7702. /**
  7703.  * Gets the default URL to learn more about updating the site to use HTTPS.
  7704.  *
  7705.  * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_https_url()} when relying on the URL.
  7706.  * This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
  7707.  * default one.
  7708.  *
  7709.  * @since 5.7.0
  7710.  * @access private
  7711.  *
  7712.  * @return string Default URL to learn more about updating to HTTPS.
  7713.  */
  7714. function wp_get_default_update_https_url() {
  7715.     /* translators: Documentation explaining HTTPS and why it should be used. */
  7716.     return __'https://developer.wordpress.org/advanced-administration/security/https/' );
  7717. }
  7718. /**
  7719.  * Gets the URL for directly updating the site to use HTTPS.
  7720.  *
  7721.  * A URL will only be returned if the `WP_DIRECT_UPDATE_HTTPS_URL` environment variable is specified or
  7722.  * by using the {@see 'wp_direct_update_https_url'} filter. This allows hosts to send users directly to
  7723.  * the page where they can update their site to use HTTPS.
  7724.  *
  7725.  * @since 5.7.0
  7726.  *
  7727.  * @return string URL for directly updating to HTTPS or empty string.
  7728.  */
  7729. function wp_get_direct_update_https_url() {
  7730.     $direct_update_url '';
  7731.     if ( false !== getenv'WP_DIRECT_UPDATE_HTTPS_URL' ) ) {
  7732.         $direct_update_url getenv'WP_DIRECT_UPDATE_HTTPS_URL' );
  7733.     }
  7734.     /**
  7735.      * Filters the URL for directly updating the PHP version the site is running on from the host.
  7736.      *
  7737.      * @since 5.7.0
  7738.      *
  7739.      * @param string $direct_update_url URL for directly updating PHP.
  7740.      */
  7741.     $direct_update_url apply_filters'wp_direct_update_https_url'$direct_update_url );
  7742.     return $direct_update_url;
  7743. }
  7744. /**
  7745.  * Gets the size of a directory.
  7746.  *
  7747.  * A helper function that is used primarily to check whether
  7748.  * a blog has exceeded its allowed upload space.
  7749.  *
  7750.  * @since MU (3.0.0)
  7751.  * @since 5.2.0 $max_execution_time parameter added.
  7752.  *
  7753.  * @param string $directory Full path of a directory.
  7754.  * @param int    $max_execution_time Maximum time to run before giving up. In seconds.
  7755.  *                                   The timeout is global and is measured from the moment WordPress started to load.
  7756.  * @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
  7757.  */
  7758. function get_dirsize$directory$max_execution_time null ) {
  7759.     /*
  7760.      * Exclude individual site directories from the total when checking the main site of a network,
  7761.      * as they are subdirectories and should not be counted.
  7762.      */
  7763.     if ( is_multisite() && is_main_site() ) {
  7764.         $size recurse_dirsize$directory$directory '/sites'$max_execution_time );
  7765.     } else {
  7766.         $size recurse_dirsize$directorynull$max_execution_time );
  7767.     }
  7768.     return $size;
  7769. }
  7770. /**
  7771.  * Gets the size of a directory recursively.
  7772.  *
  7773.  * Used by get_dirsize() to get a directory size when it contains other directories.
  7774.  *
  7775.  * @since MU (3.0.0)
  7776.  * @since 4.3.0 The `$exclude` parameter was added.
  7777.  * @since 5.2.0 The `$max_execution_time` parameter was added.
  7778.  * @since 5.6.0 The `$directory_cache` parameter was added.
  7779.  *
  7780.  * @param string          $directory          Full path of a directory.
  7781.  * @param string|string[] $exclude            Optional. Full path of a subdirectory to exclude from the total,
  7782.  *                                            or array of paths. Expected without trailing slash(es).
  7783.  *                                            Default null.
  7784.  * @param int             $max_execution_time Optional. Maximum time to run before giving up. In seconds.
  7785.  *                                            The timeout is global and is measured from the moment
  7786.  *                                            WordPress started to load. Defaults to the value of
  7787.  *                                            `max_execution_time` PHP setting.
  7788.  * @param array           $directory_cache    Optional. Array of cached directory paths.
  7789.  *                                            Defaults to the value of `dirsize_cache` transient.
  7790.  * @return int|false|null Size in bytes if a valid directory. False if not. Null if timeout.
  7791.  */
  7792. function recurse_dirsize$directory$exclude null$max_execution_time null, &$directory_cache null ) {
  7793.     $directory  untrailingslashit$directory );
  7794.     $save_cache false;
  7795.     if ( ! isset( $directory_cache ) ) {
  7796.         $directory_cache get_transient'dirsize_cache' );
  7797.         $save_cache      true;
  7798.     }
  7799.     if ( isset( $directory_cache$directory ] ) && is_int$directory_cache$directory ] ) ) {
  7800.         return $directory_cache$directory ];
  7801.     }
  7802.     if ( ! file_exists$directory ) || ! is_dir$directory ) || ! is_readable$directory ) ) {
  7803.         return false;
  7804.     }
  7805.     if (
  7806.         ( is_string$exclude ) && $directory === $exclude ) ||
  7807.         ( is_array$exclude ) && in_array$directory$excludetrue ) )
  7808.     ) {
  7809.         return false;
  7810.     }
  7811.     if ( null === $max_execution_time ) {
  7812.         // Keep the previous behavior but attempt to prevent fatal errors from timeout if possible.
  7813.         if ( function_exists'ini_get' ) ) {
  7814.             $max_execution_time ini_get'max_execution_time' );
  7815.         } else {
  7816.             // Disable...
  7817.             $max_execution_time 0;
  7818.         }
  7819.         // Leave 1 second "buffer" for other operations if $max_execution_time has reasonable value.
  7820.         if ( $max_execution_time 10 ) {
  7821.             $max_execution_time -= 1;
  7822.         }
  7823.     }
  7824.     /**
  7825.      * Filters the amount of storage space used by one directory and all its children, in megabytes.
  7826.      *
  7827.      * Return the actual used space to short-circuit the recursive PHP file size calculation
  7828.      * and use something else, like a CDN API or native operating system tools for better performance.
  7829.      *
  7830.      * @since 5.6.0
  7831.      *
  7832.      * @param int|false            $space_used         The amount of used space, in bytes. Default false.
  7833.      * @param string               $directory          Full path of a directory.
  7834.      * @param string|string[]|null $exclude            Full path of a subdirectory to exclude from the total,
  7835.      *                                                 or array of paths.
  7836.      * @param int                  $max_execution_time Maximum time to run before giving up. In seconds.
  7837.      * @param array                $directory_cache    Array of cached directory paths.
  7838.      */
  7839.     $size apply_filters'pre_recurse_dirsize'false$directory$exclude$max_execution_time$directory_cache );
  7840.     if ( false === $size ) {
  7841.         $size 0;
  7842.         $handle opendir$directory );
  7843.         if ( $handle ) {
  7844.             while ( ( $file readdir$handle ) ) !== false ) {
  7845.                 $path $directory '/' $file;
  7846.                 if ( '.' !== $file && '..' !== $file ) {
  7847.                     if ( is_file$path ) ) {
  7848.                         $size += filesize$path );
  7849.                     } elseif ( is_dir$path ) ) {
  7850.                         $handlesize recurse_dirsize$path$exclude$max_execution_time$directory_cache );
  7851.                         if ( $handlesize ) {
  7852.                             $size += $handlesize;
  7853.                         }
  7854.                     }
  7855.                     if ( $max_execution_time &&
  7856.                         ( microtimetrue ) - WP_START_TIMESTAMP ) > $max_execution_time
  7857.                     ) {
  7858.                         // Time exceeded. Give up instead of risking a fatal timeout.
  7859.                         $size null;
  7860.                         break;
  7861.                     }
  7862.                 }
  7863.             }
  7864.             closedir$handle );
  7865.         }
  7866.     }
  7867.     if ( ! is_array$directory_cache ) ) {
  7868.         $directory_cache = array();
  7869.     }
  7870.     $directory_cache$directory ] = $size;
  7871.     // Only write the transient on the top level call and not on recursive calls.
  7872.     if ( $save_cache ) {
  7873.         $expiration = ( wp_using_ext_object_cache() ) ? 10 YEAR_IN_SECONDS;
  7874.         set_transient'dirsize_cache'$directory_cache$expiration );
  7875.     }
  7876.     return $size;
  7877. }
  7878. /**
  7879.  * Cleans directory size cache used by recurse_dirsize().
  7880.  *
  7881.  * Removes the current directory and all parent directories from the `dirsize_cache` transient.
  7882.  *
  7883.  * @since 5.6.0
  7884.  * @since 5.9.0 Added input validation with a notice for invalid input.
  7885.  *
  7886.  * @param string $path Full path of a directory or file.
  7887.  */
  7888. function clean_dirsize_cache$path ) {
  7889.     if ( ! is_string$path ) || empty( $path ) ) {
  7890.         wp_trigger_error(
  7891.             '',
  7892.             sprintf(
  7893.                 /* translators: 1: Function name, 2: A variable type, like "boolean" or "integer". */
  7894.                 __'%1$s only accepts a non-empty path string, received %2$s.' ),
  7895.                 '<code>clean_dirsize_cache()</code>',
  7896.                 '<code>' gettype$path ) . '</code>'
  7897.             )
  7898.         );
  7899.         return;
  7900.     }
  7901.     $directory_cache get_transient'dirsize_cache' );
  7902.     if ( empty( $directory_cache ) ) {
  7903.         return;
  7904.     }
  7905.     $expiration = ( wp_using_ext_object_cache() ) ? 10 YEAR_IN_SECONDS;
  7906.     if (
  7907.         ! str_contains$path'/' ) &&
  7908.         ! str_contains$path'\\' )
  7909.     ) {
  7910.         unset( $directory_cache$path ] );
  7911.         set_transient'dirsize_cache'$directory_cache$expiration );
  7912.         return;
  7913.     }
  7914.     $last_path null;
  7915.     $path      untrailingslashit$path );
  7916.     unset( $directory_cache$path ] );
  7917.     while (
  7918.         $last_path !== $path &&
  7919.         DIRECTORY_SEPARATOR !== $path &&
  7920.         '.' !== $path &&
  7921.         '..' !== $path
  7922.     ) {
  7923.         $last_path $path;
  7924.         $path      dirname$path );
  7925.         unset( $directory_cache$path ] );
  7926.     }
  7927.     set_transient'dirsize_cache'$directory_cache$expiration );
  7928. }
  7929. /**
  7930.  * Returns the current WordPress version.
  7931.  *
  7932.  * Returns an unmodified value of `$wp_version`. Some plugins modify the global
  7933.  * in an attempt to improve security through obscurity. This practice can cause
  7934.  * errors in WordPress, so the ability to get an unmodified version is needed.
  7935.  *
  7936.  * @since 6.7.0
  7937.  *
  7938.  * @return string The current WordPress version.
  7939.  */
  7940. function wp_get_wp_version() {
  7941.     static $wp_version;
  7942.     if ( ! isset( $wp_version ) ) {
  7943.         require ABSPATH WPINC '/version.php';
  7944.     }
  7945.     return $wp_version;
  7946. }
  7947. /**
  7948.  * Checks compatibility with the current WordPress version.
  7949.  *
  7950.  * @since 5.2.0
  7951.  *
  7952.  * @global string $_wp_tests_wp_version The WordPress version string. Used only in Core tests.
  7953.  *
  7954.  * @param string $required Minimum required WordPress version.
  7955.  * @return bool True if required version is compatible or empty, false if not.
  7956.  */
  7957. function is_wp_version_compatible$required ) {
  7958.     if (
  7959.         defined'WP_RUN_CORE_TESTS' )
  7960.         && WP_RUN_CORE_TESTS
  7961.         && isset( $GLOBALS['_wp_tests_wp_version'] )
  7962.     ) {
  7963.         $wp_version $GLOBALS['_wp_tests_wp_version'];
  7964.     } else {
  7965.         $wp_version wp_get_wp_version();
  7966.     }
  7967.     // Strip off any -alpha, -RC, -beta, -src suffixes.
  7968.     list( $version ) = explode'-'$wp_version );
  7969.     if ( is_string$required ) ) {
  7970.         $trimmed trim$required );
  7971.         if ( substr_count$trimmed'.' ) > && str_ends_with$trimmed'.0' ) ) {
  7972.             $required substr$trimmed0, -);
  7973.         }
  7974.     }
  7975.     return empty( $required ) || version_compare$version$required'>=' );
  7976. }
  7977. /**
  7978.  * Checks compatibility with the current PHP version.
  7979.  *
  7980.  * @since 5.2.0
  7981.  *
  7982.  * @param string $required Minimum required PHP version.
  7983.  * @return bool True if required version is compatible or empty, false if not.
  7984.  */
  7985. function is_php_version_compatible$required ) {
  7986.     return empty( $required ) || version_comparePHP_VERSION$required'>=' );
  7987. }
  7988. /**
  7989.  * Checks if two numbers are nearly the same.
  7990.  *
  7991.  * This is similar to using `round()` but the precision is more fine-grained.
  7992.  *
  7993.  * @since 5.3.0
  7994.  *
  7995.  * @param int|float $expected  The expected value.
  7996.  * @param int|float $actual    The actual number.
  7997.  * @param int|float $precision Optional. The allowed variation. Default 1.
  7998.  * @return bool Whether the numbers match within the specified precision.
  7999.  */
  8000. function wp_fuzzy_number_match$expected$actual$precision ) {
  8001.     return abs( (float) $expected - (float) $actual ) <= $precision;
  8002. }
  8003. /**
  8004.  * Creates and returns the markup for an admin notice.
  8005.  *
  8006.  * @since 6.4.0
  8007.  *
  8008.  * @param string $message The message.
  8009.  * @param array  $args {
  8010.  *     Optional. An array of arguments for the admin notice. Default empty array.
  8011.  *
  8012.  *     @type string   $type               Optional. The type of admin notice.
  8013.  *                                        For example, 'error', 'success', 'warning', 'info'.
  8014.  *                                        Default empty string.
  8015.  *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
  8016.  *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
  8017.  *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
  8018.  *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
  8019.  *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
  8020.  * }
  8021.  * @return string The markup for an admin notice.
  8022.  */
  8023. function wp_get_admin_notice$message$args = array() ) {
  8024.     $defaults = array(
  8025.         'type'               => '',
  8026.         'dismissible'        => false,
  8027.         'id'                 => '',
  8028.         'additional_classes' => array(),
  8029.         'attributes'         => array(),
  8030.         'paragraph_wrap'     => true,
  8031.     );
  8032.     $args wp_parse_args$args$defaults );
  8033.     /**
  8034.      * Filters the arguments for an admin notice.
  8035.      *
  8036.      * @since 6.4.0
  8037.      *
  8038.      * @param array  $args    The arguments for the admin notice.
  8039.      * @param string $message The message for the admin notice.
  8040.      */
  8041.     $args       apply_filters'wp_admin_notice_args'$args$message );
  8042.     $id         '';
  8043.     $classes    'notice';
  8044.     $attributes '';
  8045.     if ( is_string$args['id'] ) ) {
  8046.         $trimmed_id trim$args['id'] );
  8047.         if ( '' !== $trimmed_id ) {
  8048.             $id 'id="' $trimmed_id '" ';
  8049.         }
  8050.     }
  8051.     if ( is_string$args['type'] ) ) {
  8052.         $type trim$args['type'] );
  8053.         if ( str_contains$type' ' ) ) {
  8054.             _doing_it_wrong(
  8055.                 __FUNCTION__,
  8056.                 sprintf(
  8057.                     /* translators: %s: The "type" key. */
  8058.                     __'The %s key must be a string without spaces.' ),
  8059.                     '<code>type</code>'
  8060.                 ),
  8061.                 '6.4.0'
  8062.             );
  8063.         }
  8064.         if ( '' !== $type ) {
  8065.             $classes .= ' notice-' $type;
  8066.         }
  8067.     }
  8068.     if ( true === $args['dismissible'] ) {
  8069.         $classes .= ' is-dismissible';
  8070.     }
  8071.     if ( is_array$args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
  8072.         $classes .= ' ' implode' '$args['additional_classes'] );
  8073.     }
  8074.     if ( is_array$args['attributes'] ) && ! empty( $args['attributes'] ) ) {
  8075.         $attributes '';
  8076.         foreach ( $args['attributes'] as $attr => $val ) {
  8077.             if ( is_bool$val ) ) {
  8078.                 $attributes .= $val ' ' $attr '';
  8079.             } elseif ( is_int$attr ) ) {
  8080.                 $attributes .= ' ' esc_attrtrim$val ) );
  8081.             } elseif ( $val ) {
  8082.                 $attributes .= ' ' $attr '="' esc_attrtrim$val ) ) . '"';
  8083.             }
  8084.         }
  8085.     }
  8086.     if ( false !== $args['paragraph_wrap'] ) {
  8087.         $message "<p>$message</p>";
  8088.     }
  8089.     $markup sprintf'<div %1$sclass="%2$s"%3$s>%4$s</div>'$id$classes$attributes$message );
  8090.     /**
  8091.      * Filters the markup for an admin notice.
  8092.      *
  8093.      * @since 6.4.0
  8094.      *
  8095.      * @param string $markup  The HTML markup for the admin notice.
  8096.      * @param string $message The message for the admin notice.
  8097.      * @param array  $args    The arguments for the admin notice.
  8098.      */
  8099.     return apply_filters'wp_admin_notice_markup'$markup$message$args );
  8100. }
  8101. /**
  8102.  * Outputs an admin notice.
  8103.  *
  8104.  * @since 6.4.0
  8105.  *
  8106.  * @param string $message The message to output.
  8107.  * @param array  $args {
  8108.  *     Optional. An array of arguments for the admin notice. Default empty array.
  8109.  *
  8110.  *     @type string   $type               Optional. The type of admin notice.
  8111.  *                                        For example, 'error', 'success', 'warning', 'info'.
  8112.  *                                        Default empty string.
  8113.  *     @type bool     $dismissible        Optional. Whether the admin notice is dismissible. Default false.
  8114.  *     @type string   $id                 Optional. The value of the admin notice's ID attribute. Default empty string.
  8115.  *     @type string[] $additional_classes Optional. A string array of class names. Default empty array.
  8116.  *     @type string[] $attributes         Optional. Additional attributes for the notice div. Default empty array.
  8117.  *     @type bool     $paragraph_wrap     Optional. Whether to wrap the message in paragraph tags. Default true.
  8118.  * }
  8119.  */
  8120. function wp_admin_notice$message$args = array() ) {
  8121.     /**
  8122.      * Fires before an admin notice is output.
  8123.      *
  8124.      * @since 6.4.0
  8125.      *
  8126.      * @param string $message The message for the admin notice.
  8127.      * @param array  $args    The arguments for the admin notice.
  8128.      */
  8129.     do_action'wp_admin_notice'$message$args );
  8130.     echo wp_kses_postwp_get_admin_notice$message$args ) );
  8131. }
  8132. /**
  8133.  * Checks if a mime type is for a HEIC/HEIF image.
  8134.  *
  8135.  * @since 6.7.0
  8136.  *
  8137.  * @param string $mime_type The mime type to check.
  8138.  * @return bool Whether the mime type is for a HEIC/HEIF image.
  8139.  */
  8140. function wp_is_heic_image_mime_type$mime_type ) {
  8141.     $heic_mime_types = array(
  8142.         'image/heic',
  8143.         'image/heif',
  8144.         'image/heic-sequence',
  8145.         'image/heif-sequence',
  8146.     );
  8147.     return in_array$mime_type$heic_mime_typestrue );
  8148. }
  8149. /**
  8150.  * Returns a cryptographically secure hash of a message using a fast generic hash function.
  8151.  *
  8152.  * Use the wp_verify_fast_hash() function to verify the hash.
  8153.  *
  8154.  * This function does not salt the value prior to being hashed, therefore input to this function must originate from
  8155.  * a random generator with sufficiently high entropy, preferably greater than 128 bits. This function is used internally
  8156.  * in WordPress to hash security keys and application passwords which are generated with high entropy.
  8157.  *
  8158.  * Important:
  8159.  *
  8160.  *  - This function must not be used for hashing user-generated passwords. Use wp_hash_password() for that.
  8161.  *  - This function must not be used for hashing other low-entropy input. Use wp_hash() for that.
  8162.  *
  8163.  * The BLAKE2b algorithm is used by Sodium to hash the message.
  8164.  *
  8165.  * @since 6.8.0
  8166.  *
  8167.  * @throws TypeError Thrown by Sodium if the message is not a string.
  8168.  *
  8169.  * @param string $message The message to hash.
  8170.  * @return string The hash of the message.
  8171.  */
  8172. function wp_fast_hash(
  8173.     #[\SensitiveParameter]
  8174.     string $message
  8175. ): string {
  8176.     $hashed sodium_crypto_generichash$message'wp_fast_hash_6.8+'30 );
  8177.     return '$generic$' sodium_bin2base64$hashedSODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING );
  8178. }
  8179. /**
  8180.  * Checks whether a plaintext message matches the hashed value. Used to verify values hashed via wp_fast_hash().
  8181.  *
  8182.  * The function uses Sodium to hash the message and compare it to the hashed value. If the hash is not a generic hash,
  8183.  * the hash is treated as a phpass portable hash in order to provide backward compatibility for passwords and security
  8184.  * keys which were hashed using phpass prior to WordPress 6.8.0.
  8185.  *
  8186.  * @since 6.8.0
  8187.  *
  8188.  * @throws TypeError Thrown by Sodium if the message is not a string.
  8189.  *
  8190.  * @param string $message The plaintext message.
  8191.  * @param string $hash    Hash of the message to check against.
  8192.  * @return bool Whether the message matches the hashed message.
  8193.  */
  8194. function wp_verify_fast_hash(
  8195.     #[\SensitiveParameter]
  8196.     string $message,
  8197.     string $hash
  8198. ): bool {
  8199.     if ( ! str_starts_with$hash'$generic$' ) ) {
  8200.         // Back-compat for old phpass hashes.
  8201.         require_once ABSPATH WPINC '/class-phpass.php';
  8202.         return ( new PasswordHash8true ) )->CheckPassword$message$hash );
  8203.     }
  8204.     return hash_equals$hashwp_fast_hash$message ) );
  8205. }
  8206. /**
  8207.  * Generates a unique ID based on the structure and values of a given array.
  8208.  *
  8209.  * This function serializes the array into a JSON string and generates a hash
  8210.  * that serves as a unique identifier. Optionally, a prefix can be added to
  8211.  * the generated ID for context or categorization.
  8212.  *
  8213.  * @since 6.8.0
  8214.  *
  8215.  * @param array  $data   The input array to generate an ID from.
  8216.  * @param string $prefix Optional. A prefix to prepend to the generated ID. Default ''.
  8217.  *
  8218.  * @return string The generated unique ID for the array.
  8219.  */
  8220. function wp_unique_id_from_values( array $datastring $prefix '' ): string {
  8221.     if ( empty( $data ) ) {
  8222.         _doing_it_wrong(
  8223.             __FUNCTION__,
  8224.             sprintf(
  8225.                 /* translators: %s: parameter name. */
  8226.                 __'The %s argument must not be empty.' ),
  8227.                 '$data'
  8228.             ),
  8229.             '6.8.0'
  8230.         );
  8231.     }
  8232.     $serialized wp_json_encode$data );
  8233.     $hash       substrmd5$serialized ), 0);
  8234.     return $prefix $hash;
  8235. }