aboutsummaryrefslogtreecommitdiff
path: root/srcs/wordpress/wp-includes/functions.php
diff options
context:
space:
mode:
Diffstat (limited to 'srcs/wordpress/wp-includes/functions.php')
-rw-r--r--srcs/wordpress/wp-includes/functions.php7403
1 files changed, 7403 insertions, 0 deletions
diff --git a/srcs/wordpress/wp-includes/functions.php b/srcs/wordpress/wp-includes/functions.php
new file mode 100644
index 0000000..939ed50
--- /dev/null
+++ b/srcs/wordpress/wp-includes/functions.php
@@ -0,0 +1,7403 @@
+<?php
+/**
+ * Main WordPress API
+ *
+ * @package WordPress
+ */
+
+require( ABSPATH . WPINC . '/option.php' );
+
+/**
+ * Convert given MySQL date string into a different format.
+ *
+ * `$format` should be a PHP date format string.
+ * 'U' and 'G' formats will return a sum of timestamp with timezone offset.
+ * `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`).
+ *
+ * Historically UTC time could be passed to the function to produce Unix timestamp.
+ *
+ * If `$translate` is true then the given date and format string will
+ * be passed to `wp_date()` for translation.
+ *
+ * @since 0.71
+ *
+ * @param string $format Format of the date to return.
+ * @param string $date Date string to convert.
+ * @param bool $translate Whether the return date should be translated. Default true.
+ * @return string|int|false Formatted date string or sum of Unix timestamp and timezone offset.
+ * False on failure.
+ */
+function mysql2date( $format, $date, $translate = true ) {
+ if ( empty( $date ) ) {
+ return false;
+ }
+
+ $datetime = date_create( $date, wp_timezone() );
+
+ if ( false === $datetime ) {
+ return false;
+ }
+
+ // Returns a sum of timestamp with timezone offset. Ideally should never be used.
+ if ( 'G' === $format || 'U' === $format ) {
+ return $datetime->getTimestamp() + $datetime->getOffset();
+ }
+
+ if ( $translate ) {
+ return wp_date( $format, $datetime->getTimestamp() );
+ }
+
+ return $datetime->format( $format );
+}
+
+/**
+ * Retrieves the current time based on specified type.
+ *
+ * The 'mysql' type will return the time in the format for MySQL DATETIME field.
+ * The 'timestamp' type will return the current timestamp or a sum of timestamp
+ * and timezone offset, depending on `$gmt`.
+ * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
+ *
+ * If $gmt is set to either '1' or 'true', then both types will use GMT time.
+ * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
+ *
+ * @since 1.0.0
+ *
+ * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp',
+ * or PHP date format string (e.g. 'Y-m-d').
+ * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false.
+ * @return int|string Integer if $type is 'timestamp', string otherwise.
+ */
+function current_time( $type, $gmt = 0 ) {
+ // Don't use non-GMT timestamp, unless you know the difference and really need to.
+ if ( 'timestamp' === $type || 'U' === $type ) {
+ return $gmt ? time() : time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
+ }
+
+ if ( 'mysql' === $type ) {
+ $type = 'Y-m-d H:i:s';
+ }
+
+ $timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone();
+ $datetime = new DateTime( 'now', $timezone );
+
+ return $datetime->format( $type );
+}
+
+/**
+ * Retrieves the current time as an object with the timezone from settings.
+ *
+ * @since 5.3.0
+ *
+ * @return DateTimeImmutable Date and time object.
+ */
+function current_datetime() {
+ return new DateTimeImmutable( 'now', wp_timezone() );
+}
+
+/**
+ * Retrieves the timezone from site settings as a string.
+ *
+ * Uses the `timezone_string` option to get a proper timezone if available,
+ * otherwise falls back to an offset.
+ *
+ * @since 5.3.0
+ *
+ * @return string PHP timezone string or a ±HH:MM offset.
+ */
+function wp_timezone_string() {
+ $timezone_string = get_option( 'timezone_string' );
+
+ if ( $timezone_string ) {
+ return $timezone_string;
+ }
+
+ $offset = (float) get_option( 'gmt_offset' );
+ $hours = (int) $offset;
+ $minutes = ( $offset - $hours );
+
+ $sign = ( $offset < 0 ) ? '-' : '+';
+ $abs_hour = abs( $hours );
+ $abs_mins = abs( $minutes * 60 );
+ $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
+
+ return $tz_offset;
+}
+
+/**
+ * Retrieves the timezone from site settings as a `DateTimeZone` object.
+ *
+ * Timezone can be based on a PHP timezone string or a ±HH:MM offset.
+ *
+ * @since 5.3.0
+ *
+ * @return DateTimeZone Timezone object.
+ */
+function wp_timezone() {
+ return new DateTimeZone( wp_timezone_string() );
+}
+
+/**
+ * Retrieves the date in localized format, based on a sum of Unix timestamp and
+ * timezone offset in seconds.
+ *
+ * If the locale specifies the locale month and weekday, then the locale will
+ * take over the format for the date. If it isn't, then the date format string
+ * will be used instead.
+ *
+ * Note that due to the way WP typically generates a sum of timestamp and offset
+ * with `strtotime()`, it implies offset added at a _current_ time, not at the time
+ * the timestamp represents. Storing such timestamps or calculating them differently
+ * will lead to invalid output.
+ *
+ * @since 0.71
+ * @since 5.3.0 Converted into a wrapper for wp_date().
+ *
+ * @global WP_Locale $wp_locale WordPress date and time locale object.
+ *
+ * @param string $format Format to display the date.
+ * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset
+ * in seconds. Default false.
+ * @param bool $gmt Optional. Whether to use GMT timezone. Only applies
+ * if timestamp is not provided. Default false.
+ * @return string The date, translated if locale specifies it.
+ */
+function date_i18n( $format, $timestamp_with_offset = false, $gmt = false ) {
+ $timestamp = $timestamp_with_offset;
+
+ // If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true).
+ if ( ! is_numeric( $timestamp ) ) {
+ $timestamp = current_time( 'timestamp', $gmt );
+ }
+
+ /*
+ * This is a legacy implementation quirk that the returned timestamp is also with offset.
+ * Ideally this function should never be used to produce a timestamp.
+ */
+ if ( 'U' === $format ) {
+ $date = $timestamp;
+ } elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC.
+ $date = wp_date( $format, null, new DateTimeZone( 'UTC' ) );
+ } elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone.
+ $date = wp_date( $format );
+ } else {
+ /*
+ * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone.
+ * This is the best attempt to reverse that operation into a local time to use.
+ */
+ $local_time = gmdate( 'Y-m-d H:i:s', $timestamp );
+ $timezone = wp_timezone();
+ $datetime = date_create( $local_time, $timezone );
+ $date = wp_date( $format, $datetime->getTimestamp(), $timezone );
+ }
+
+ /**
+ * Filters the date formatted based on the locale.
+ *
+ * @since 2.8.0
+ *
+ * @param string $date Formatted date string.
+ * @param string $format Format to display the date.
+ * @param int $timestamp A sum of Unix timestamp and timezone offset in seconds.
+ * Might be without offset if input omitted timestamp but requested GMT.
+ * @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was not provided.
+ * Default false.
+ */
+ $date = apply_filters( 'date_i18n', $date, $format, $timestamp, $gmt );
+
+ return $date;
+}
+
+/**
+ * Retrieves the date, in localized format.
+ *
+ * This is a newer function, intended to replace `date_i18n()` without legacy quirks in it.
+ *
+ * Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed
+ * with timezone offset.
+ *
+ * @since 5.3.0
+ *
+ * @param string $format PHP date format.
+ * @param int $timestamp Optional. Unix timestamp. Defaults to current time.
+ * @param DateTimeZone $timezone Optional. Timezone to output result in. Defaults to timezone
+ * from site settings.
+ * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
+ */
+function wp_date( $format, $timestamp = null, $timezone = null ) {
+ global $wp_locale;
+
+ if ( null === $timestamp ) {
+ $timestamp = time();
+ } elseif ( ! is_numeric( $timestamp ) ) {
+ return false;
+ }
+
+ if ( ! $timezone ) {
+ $timezone = wp_timezone();
+ }
+
+ $datetime = date_create( '@' . $timestamp );
+ $datetime->setTimezone( $timezone );
+
+ if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) {
+ $date = $datetime->format( $format );
+ } else {
+ // We need to unpack shorthand `r` format because it has parts that might be localized.
+ $format = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $format );
+
+ $new_format = '';
+ $format_length = strlen( $format );
+ $month = $wp_locale->get_month( $datetime->format( 'm' ) );
+ $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) );
+
+ for ( $i = 0; $i < $format_length; $i ++ ) {
+ switch ( $format[ $i ] ) {
+ case 'D':
+ $new_format .= addcslashes( $wp_locale->get_weekday_abbrev( $weekday ), '\\A..Za..z' );
+ break;
+ case 'F':
+ $new_format .= addcslashes( $month, '\\A..Za..z' );
+ break;
+ case 'l':
+ $new_format .= addcslashes( $weekday, '\\A..Za..z' );
+ break;
+ case 'M':
+ $new_format .= addcslashes( $wp_locale->get_month_abbrev( $month ), '\\A..Za..z' );
+ break;
+ case 'a':
+ $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'a' ) ), '\\A..Za..z' );
+ break;
+ case 'A':
+ $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'A' ) ), '\\A..Za..z' );
+ break;
+ case '\\':
+ $new_format .= $format[ $i ];
+
+ // If character follows a slash, we add it without translating.
+ if ( $i < $format_length ) {
+ $new_format .= $format[ ++$i ];
+ }
+ break;
+ default:
+ $new_format .= $format[ $i ];
+ break;
+ }
+ }
+
+ $date = $datetime->format( $new_format );
+ $date = wp_maybe_decline_date( $date );
+ }
+
+ /**
+ * Filters the date formatted based on the locale.
+ *
+ * @since 5.3.0
+ *
+ * @param string $date Formatted date string.
+ * @param string $format Format to display the date.
+ * @param int $timestamp Unix timestamp.
+ * @param DateTimeZone $timezone Timezone.
+ *
+ */
+ $date = apply_filters( 'wp_date', $date, $format, $timestamp, $timezone );
+
+ return $date;
+}
+
+/**
+ * Determines if the date should be declined.
+ *
+ * If the locale specifies that month names require a genitive case in certain
+ * formats (like 'j F Y'), the month name will be replaced with a correct form.
+ *
+ * @since 4.4.0
+ *
+ * @global WP_Locale $wp_locale WordPress date and time locale object.
+ *
+ * @param string $date Formatted date string.
+ * @return string The date, declined if locale specifies it.
+ */
+function wp_maybe_decline_date( $date ) {
+ global $wp_locale;
+
+ // i18n functions are not available in SHORTINIT mode
+ if ( ! function_exists( '_x' ) ) {
+ return $date;
+ }
+
+ /*
+ * translators: If months in your language require a genitive case,
+ * translate this to 'on'. Do not translate into your own language.
+ */
+ if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
+
+ $months = $wp_locale->month;
+ $months_genitive = $wp_locale->month_genitive;
+
+ /*
+ * Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name)
+ * and decline the month.
+ */
+ if ( preg_match( '#\b\d{1,2}\.? [^\d ]+\b#u', $date ) ) {
+ foreach ( $months as $key => $month ) {
+ $months[ $key ] = '# ' . preg_quote( $month, '#' ) . '\b#u';
+ }
+
+ foreach ( $months_genitive as $key => $month ) {
+ $months_genitive[ $key ] = ' ' . $month;
+ }
+
+ $date = preg_replace( $months, $months_genitive, $date );
+ }
+
+ /*
+ * Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix)
+ * and change it to declined 'j F'.
+ */
+ if ( preg_match( '#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u', trim( $date ) ) ) {
+ foreach ( $months as $key => $month ) {
+ $months[ $key ] = '#\b' . preg_quote( $month, '#' ) . ' (\d{1,2})(st|nd|rd|th)?\b#u';
+ }
+
+ foreach ( $months_genitive as $key => $month ) {
+ $months_genitive[ $key ] = '$1 ' . $month;
+ }
+
+ $date = preg_replace( $months, $months_genitive, $date );
+ }
+ }
+
+ // Used for locale-specific rules
+ $locale = get_locale();
+
+ if ( 'ca' === $locale ) {
+ // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
+ $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
+ }
+
+ return $date;
+}
+
+/**
+ * Convert float number to format based on the locale.
+ *
+ * @since 2.3.0
+ *
+ * @global WP_Locale $wp_locale WordPress date and time locale object.
+ *
+ * @param float $number The number to convert based on locale.
+ * @param int $decimals Optional. Precision of the number of decimal places. Default 0.
+ * @return string Converted number in string format.
+ */
+function number_format_i18n( $number, $decimals = 0 ) {
+ global $wp_locale;
+
+ if ( isset( $wp_locale ) ) {
+ $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
+ } else {
+ $formatted = number_format( $number, absint( $decimals ) );
+ }
+
+ /**
+ * Filters the number formatted based on the locale.
+ *
+ * @since 2.8.0
+ * @since 4.9.0 The `$number` and `$decimals` parameters were added.
+ *
+ * @param string $formatted Converted number in string format.
+ * @param float $number The number to convert based on locale.
+ * @param int $decimals Precision of the number of decimal places.
+ */
+ return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
+}
+
+/**
+ * Convert number of bytes largest unit bytes will fit into.
+ *
+ * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
+ * number of bytes to human readable number by taking the number of that unit
+ * that the bytes will go into it. Supports TB value.
+ *
+ * Please note that integers in PHP are limited to 32 bits, unless they are on
+ * 64 bit architecture, then they have 64 bit size. If you need to place the
+ * larger size then what PHP integer type will hold, then use a string. It will
+ * be converted to a double, which should always have 64 bit length.
+ *
+ * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
+ *
+ * @since 2.3.0
+ *
+ * @param int|string $bytes Number of bytes. Note max integer size for integers.
+ * @param int $decimals Optional. Precision of number of decimal places. Default 0.
+ * @return string|false False on failure. Number string on success.
+ */
+function size_format( $bytes, $decimals = 0 ) {
+ $quant = array(
+ 'TB' => TB_IN_BYTES,
+ 'GB' => GB_IN_BYTES,
+ 'MB' => MB_IN_BYTES,
+ 'KB' => KB_IN_BYTES,
+ 'B' => 1,
+ );
+
+ if ( 0 === $bytes ) {
+ return number_format_i18n( 0, $decimals ) . ' B';
+ }
+
+ foreach ( $quant as $unit => $mag ) {
+ if ( doubleval( $bytes ) >= $mag ) {
+ return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Convert a duration to human readable format.
+ *
+ * @since 5.1.0
+ *
+ * @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
+ * with a possible prepended negative sign (-).
+ * @return string|false A human readable duration string, false on failure.
+ */
+function human_readable_duration( $duration = '' ) {
+ if ( ( empty( $duration ) || ! is_string( $duration ) ) ) {
+ return false;
+ }
+
+ $duration = trim( $duration );
+
+ // Remove prepended negative sign.
+ if ( '-' === substr( $duration, 0, 1 ) ) {
+ $duration = substr( $duration, 1 );
+ }
+
+ // Extract duration parts.
+ $duration_parts = array_reverse( explode( ':', $duration ) );
+ $duration_count = count( $duration_parts );
+
+ $hour = null;
+ $minute = null;
+ $second = null;
+
+ if ( 3 === $duration_count ) {
+ // Validate HH:ii:ss duration format.
+ if ( ! ( (bool) preg_match( '/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
+ return false;
+ }
+ // Three parts: hours, minutes & seconds.
+ list( $second, $minute, $hour ) = $duration_parts;
+ } elseif ( 2 === $duration_count ) {
+ // Validate ii:ss duration format.
+ if ( ! ( (bool) preg_match( '/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
+ return false;
+ }
+ // Two parts: minutes & seconds.
+ list( $second, $minute ) = $duration_parts;
+ } else {
+ return false;
+ }
+
+ $human_readable_duration = array();
+
+ // Add the hour part to the string.
+ if ( is_numeric( $hour ) ) {
+ /* translators: %s: Time duration in hour or hours. */
+ $human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour );
+ }
+
+ // Add the minute part to the string.
+ if ( is_numeric( $minute ) ) {
+ /* translators: %s: Time duration in minute or minutes. */
+ $human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute );
+ }
+
+ // Add the second part to the string.
+ if ( is_numeric( $second ) ) {
+ /* translators: %s: Time duration in second or seconds. */
+ $human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second );
+ }
+
+ return implode( ', ', $human_readable_duration );
+}
+
+/**
+ * Get the week start and end from the datetime or date string from MySQL.
+ *
+ * @since 0.71
+ *
+ * @param string $mysqlstring Date or datetime field type from MySQL.
+ * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
+ * @return array Keys are 'start' and 'end'.
+ */
+function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
+ // MySQL string year.
+ $my = substr( $mysqlstring, 0, 4 );
+
+ // MySQL string month.
+ $mm = substr( $mysqlstring, 8, 2 );
+
+ // MySQL string day.
+ $md = substr( $mysqlstring, 5, 2 );
+
+ // The timestamp for MySQL string day.
+ $day = mktime( 0, 0, 0, $md, $mm, $my );
+
+ // The day of the week from the timestamp.
+ $weekday = gmdate( 'w', $day );
+
+ if ( ! is_numeric( $start_of_week ) ) {
+ $start_of_week = get_option( 'start_of_week' );
+ }
+
+ if ( $weekday < $start_of_week ) {
+ $weekday += 7;
+ }
+
+ // The most recent week start day on or before $day.
+ $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
+
+ // $start + 1 week - 1 second.
+ $end = $start + WEEK_IN_SECONDS - 1;
+ return compact( 'start', 'end' );
+}
+
+/**
+ * Unserialize value only if it was serialized.
+ *
+ * @since 2.0.0
+ *
+ * @param string $original Maybe unserialized original, if is needed.
+ * @return mixed Unserialized data can be any type.
+ */
+function maybe_unserialize( $original ) {
+ if ( is_serialized( $original ) ) { // don't attempt to unserialize data that wasn't serialized going in
+ return @unserialize( $original );
+ }
+ return $original;
+}
+
+/**
+ * Check value to find if it was serialized.
+ *
+ * If $data is not an string, then returned value will always be false.
+ * Serialized data is always a string.
+ *
+ * @since 2.0.5
+ *
+ * @param string $data Value to check to see if was serialized.
+ * @param bool $strict Optional. Whether to be strict about the end of the string. Default true.
+ * @return bool False if not serialized and true if it was.
+ */
+function is_serialized( $data, $strict = true ) {
+ // if it isn't a string, it isn't serialized.
+ if ( ! is_string( $data ) ) {
+ return false;
+ }
+ $data = trim( $data );
+ if ( 'N;' == $data ) {
+ return true;
+ }
+ if ( strlen( $data ) < 4 ) {
+ return false;
+ }
+ if ( ':' !== $data[1] ) {
+ return false;
+ }
+ if ( $strict ) {
+ $lastc = substr( $data, -1 );
+ if ( ';' !== $lastc && '}' !== $lastc ) {
+ return false;
+ }
+ } else {
+ $semicolon = strpos( $data, ';' );
+ $brace = strpos( $data, '}' );
+ // Either ; or } must exist.
+ if ( false === $semicolon && false === $brace ) {
+ return false;
+ }
+ // But neither must be in the first X characters.
+ if ( false !== $semicolon && $semicolon < 3 ) {
+ return false;
+ }
+ if ( false !== $brace && $brace < 4 ) {
+ return false;
+ }
+ }
+ $token = $data[0];
+ switch ( $token ) {
+ case 's':
+ if ( $strict ) {
+ if ( '"' !== substr( $data, -2, 1 ) ) {
+ return false;
+ }
+ } elseif ( false === strpos( $data, '"' ) ) {
+ return false;
+ }
+ // or else fall through
+ case 'a':
+ case 'O':
+ return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
+ case 'b':
+ case 'i':
+ case 'd':
+ $end = $strict ? '$' : '';
+ return (bool) preg_match( "/^{$token}:[0-9.E+-]+;$end/", $data );
+ }
+ return false;
+}
+
+/**
+ * Check whether serialized data is of string type.
+ *
+ * @since 2.0.5
+ *
+ * @param string $data Serialized data.
+ * @return bool False if not a serialized string, true if it is.
+ */
+function is_serialized_string( $data ) {
+ // if it isn't a string, it isn't a serialized string.
+ if ( ! is_string( $data ) ) {
+ return false;
+ }
+ $data = trim( $data );
+ if ( strlen( $data ) < 4 ) {
+ return false;
+ } elseif ( ':' !== $data[1] ) {
+ return false;
+ } elseif ( ';' !== substr( $data, -1 ) ) {
+ return false;
+ } elseif ( $data[0] !== 's' ) {
+ return false;
+ } elseif ( '"' !== substr( $data, -2, 1 ) ) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/**
+ * Serialize data, if needed.
+ *
+ * @since 2.0.5
+ *
+ * @param string|array|object $data Data that might be serialized.
+ * @return mixed A scalar data
+ */
+function maybe_serialize( $data ) {
+ if ( is_array( $data ) || is_object( $data ) ) {
+ return serialize( $data );
+ }
+
+ // Double serialization is required for backward compatibility.
+ // See https://core.trac.wordpress.org/ticket/12930
+ // Also the world will end. See WP 3.6.1.
+ if ( is_serialized( $data, false ) ) {
+ return serialize( $data );
+ }
+
+ return $data;
+}
+
+/**
+ * Retrieve post title from XMLRPC XML.
+ *
+ * If the title element is not part of the XML, then the default post title from
+ * the $post_default_title will be used instead.
+ *
+ * @since 0.71
+ *
+ * @global string $post_default_title Default XML-RPC post title.
+ *
+ * @param string $content XMLRPC XML Request content
+ * @return string Post title
+ */
+function xmlrpc_getposttitle( $content ) {
+ global $post_default_title;
+ if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
+ $post_title = $matchtitle[1];
+ } else {
+ $post_title = $post_default_title;
+ }
+ return $post_title;
+}
+
+/**
+ * Retrieve the post category or categories from XMLRPC XML.
+ *
+ * If the category element is not found, then the default post category will be
+ * used. The return type then would be what $post_default_category. If the
+ * category is found, then it will always be an array.
+ *
+ * @since 0.71
+ *
+ * @global string $post_default_category Default XML-RPC post category.
+ *
+ * @param string $content XMLRPC XML Request content
+ * @return string|array List of categories or category name.
+ */
+function xmlrpc_getpostcategory( $content ) {
+ global $post_default_category;
+ if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
+ $post_category = trim( $matchcat[1], ',' );
+ $post_category = explode( ',', $post_category );
+ } else {
+ $post_category = $post_default_category;
+ }
+ return $post_category;
+}
+
+/**
+ * XMLRPC XML content without title and category elements.
+ *
+ * @since 0.71
+ *
+ * @param string $content XML-RPC XML Request content.
+ * @return string XMLRPC XML Request content without title and category elements.
+ */
+function xmlrpc_removepostdata( $content ) {
+ $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
+ $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
+ $content = trim( $content );
+ return $content;
+}
+
+/**
+ * Use RegEx to extract URLs from arbitrary content.
+ *
+ * @since 3.7.0
+ *
+ * @param string $content Content to extract URLs from.
+ * @return array URLs found in passed string.
+ */
+function wp_extract_urls( $content ) {
+ preg_match_all(
+ "#([\"']?)("
+ . '(?:([\w-]+:)?//?)'
+ . '[^\s()<>]+'
+ . '[.]'
+ . '(?:'
+ . '\([\w\d]+\)|'
+ . '(?:'
+ . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
+ . '(?:[:]\d+)?/?'
+ . ')+'
+ . ')'
+ . ")\\1#",
+ $content,
+ $post_links
+ );
+
+ $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
+
+ return array_values( $post_links );
+}
+
+/**
+ * Check content for video and audio links to add as enclosures.
+ *
+ * Will not add enclosures that have already been added and will
+ * remove enclosures that are no longer in the post. This is called as
+ * pingbacks and trackbacks.
+ *
+ * @since 1.5.0
+ * @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
+ * updated to accept a post ID or a WP_Post object.
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @param string $content Post content. If `null`, the `post_content` field from `$post` is used.
+ * @param int|WP_Post $post Post ID or post object.
+ * @return null|bool Returns false if post is not found.
+ */
+function do_enclose( $content = null, $post ) {
+ global $wpdb;
+
+ // @todo Tidy this code and make the debug code optional.
+ include_once( ABSPATH . WPINC . '/class-IXR.php' );
+
+ $post = get_post( $post );
+ if ( ! $post ) {
+ return false;
+ }
+
+ if ( null === $content ) {
+ $content = $post->post_content;
+ }
+
+ $post_links = array();
+
+ $pung = get_enclosed( $post->ID );
+
+ $post_links_temp = wp_extract_urls( $content );
+
+ foreach ( $pung as $link_test ) {
+ // Link is no longer in post.
+ if ( ! in_array( $link_test, $post_links_temp, true ) ) {
+ $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 ) . '%' ) );
+ foreach ( $mids as $mid ) {
+ delete_metadata_by_mid( 'post', $mid );
+ }
+ }
+ }
+
+ foreach ( (array) $post_links_temp as $link_test ) {
+ // If we haven't pung it already.
+ if ( ! in_array( $link_test, $pung, true ) ) {
+ $test = @parse_url( $link_test );
+ if ( false === $test ) {
+ continue;
+ }
+ if ( isset( $test['query'] ) ) {
+ $post_links[] = $link_test;
+ } elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
+ $post_links[] = $link_test;
+ }
+ }
+ }
+
+ /**
+ * Filters the list of enclosure links before querying the database.
+ *
+ * Allows for the addition and/or removal of potential enclosures to save
+ * to postmeta before checking the database for existing enclosures.
+ *
+ * @since 4.4.0
+ *
+ * @param array $post_links An array of enclosure links.
+ * @param int $post_ID Post ID.
+ */
+ $post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
+
+ foreach ( (array) $post_links as $url ) {
+ 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 ) . '%' ) ) ) {
+
+ $headers = wp_get_http_headers( $url );
+ if ( $headers ) {
+ $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
+ $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
+ $allowed_types = array( 'video', 'audio' );
+
+ // Check to see if we can figure out the mime type from
+ // the extension
+ $url_parts = @parse_url( $url );
+ if ( false !== $url_parts ) {
+ $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
+ if ( ! empty( $extension ) ) {
+ foreach ( wp_get_mime_types() as $exts => $mime ) {
+ if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
+ $type = $mime;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types, true ) ) {
+ add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" );
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Retrieve HTTP Headers from URL.
+ *
+ * @since 1.5.1
+ *
+ * @param string $url URL to retrieve HTTP headers from.
+ * @param bool $deprecated Not Used.
+ * @return bool|string False on failure, headers on success.
+ */
+function wp_get_http_headers( $url, $deprecated = false ) {
+ if ( ! empty( $deprecated ) ) {
+ _deprecated_argument( __FUNCTION__, '2.7.0' );
+ }
+
+ $response = wp_safe_remote_head( $url );
+
+ if ( is_wp_error( $response ) ) {
+ return false;
+ }
+
+ return wp_remote_retrieve_headers( $response );
+}
+
+/**
+ * Determines whether the publish date of the current post in the loop is different
+ * from the publish date of the previous post in the loop.
+ *
+ * For more information on this and similar theme functions, check out
+ * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
+ * Conditional Tags} article in the Theme Developer Handbook.
+ *
+ * @since 0.71
+ *
+ * @global string $currentday The day of the current post in the loop.
+ * @global string $previousday The day of the previous post in the loop.
+ *
+ * @return int 1 when new day, 0 if not a new day.
+ */
+function is_new_day() {
+ global $currentday, $previousday;
+
+ if ( $currentday !== $previousday ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Build URL query based on an associative and, or indexed array.
+ *
+ * This is a convenient function for easily building url queries. It sets the
+ * separator to '&' and uses _http_build_query() function.
+ *
+ * @since 2.3.0
+ *
+ * @see _http_build_query() Used to build the query
+ * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
+ * http_build_query() does.
+ *
+ * @param array $data URL-encode key/value pairs.
+ * @return string URL-encoded string.
+ */
+function build_query( $data ) {
+ return _http_build_query( $data, null, '&', '', false );
+}
+
+/**
+ * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @see https://secure.php.net/manual/en/function.http-build-query.php
+ *
+ * @param array|object $data An array or object of data. Converted to array.
+ * @param string $prefix Optional. Numeric index. If set, start parameter numbering with it.
+ * Default null.
+ * @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'.
+ * Default null.
+ * @param string $key Optional. Used to prefix key name. Default empty.
+ * @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true.
+ *
+ * @return string The query string.
+ */
+function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
+ $ret = array();
+
+ foreach ( (array) $data as $k => $v ) {
+ if ( $urlencode ) {
+ $k = urlencode( $k );
+ }
+ if ( is_int( $k ) && $prefix != null ) {
+ $k = $prefix . $k;
+ }
+ if ( ! empty( $key ) ) {
+ $k = $key . '%5B' . $k . '%5D';
+ }
+ if ( $v === null ) {
+ continue;
+ } elseif ( $v === false ) {
+ $v = '0';
+ }
+
+ if ( is_array( $v ) || is_object( $v ) ) {
+ array_push( $ret, _http_build_query( $v, '', $sep, $k, $urlencode ) );
+ } elseif ( $urlencode ) {
+ array_push( $ret, $k . '=' . urlencode( $v ) );
+ } else {
+ array_push( $ret, $k . '=' . $v );
+ }
+ }
+
+ if ( null === $sep ) {
+ $sep = ini_get( 'arg_separator.output' );
+ }
+
+ return implode( $sep, $ret );
+}
+
+/**
+ * Retrieves a modified URL query string.
+ *
+ * You can rebuild the URL and append query variables to the URL query by using this function.
+ * There are two ways to use this function; either a single key and value, or an associative array.
+ *
+ * Using a single key and value:
+ *
+ * add_query_arg( 'key', 'value', 'http://example.com' );
+ *
+ * Using an associative array:
+ *
+ * add_query_arg( array(
+ * 'key1' => 'value1',
+ * 'key2' => 'value2',
+ * ), 'http://example.com' );
+ *
+ * Omitting the URL from either use results in the current URL being used
+ * (the value of `$_SERVER['REQUEST_URI']`).
+ *
+ * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
+ *
+ * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
+ *
+ * Important: The return value of add_query_arg() is not escaped by default. Output should be
+ * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
+ * (XSS) attacks.
+ *
+ * @since 1.5.0
+ * @since 5.3.0 Formalized the existing and already documented parameters
+ * by adding `...$args` to the function signature.
+ *
+ * @param string|array $key Either a query variable key, or an associative array of query variables.
+ * @param string $value Optional. Either a query variable value, or a URL to act upon.
+ * @param string $url Optional. A URL to act upon.
+ * @return string New URL query string (unescaped).
+ */
+function add_query_arg( ...$args ) {
+ if ( is_array( $args[0] ) ) {
+ if ( count( $args ) < 2 || false === $args[1] ) {
+ $uri = $_SERVER['REQUEST_URI'];
+ } else {
+ $uri = $args[1];
+ }
+ } else {
+ if ( count( $args ) < 3 || false === $args[2] ) {
+ $uri = $_SERVER['REQUEST_URI'];
+ } else {
+ $uri = $args[2];
+ }
+ }
+
+ $frag = strstr( $uri, '#' );
+ if ( $frag ) {
+ $uri = substr( $uri, 0, -strlen( $frag ) );
+ } else {
+ $frag = '';
+ }
+
+ if ( 0 === stripos( $uri, 'http://' ) ) {
+ $protocol = 'http://';
+ $uri = substr( $uri, 7 );
+ } elseif ( 0 === stripos( $uri, 'https://' ) ) {
+ $protocol = 'https://';
+ $uri = substr( $uri, 8 );
+ } else {
+ $protocol = '';
+ }
+
+ if ( strpos( $uri, '?' ) !== false ) {
+ list( $base, $query ) = explode( '?', $uri, 2 );
+ $base .= '?';
+ } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
+ $base = $uri . '?';
+ $query = '';
+ } else {
+ $base = '';
+ $query = $uri;
+ }</