Guest User

Untitled

a guest
Aug 18th, 2016
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 54.94 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Main WordPress API
  4.  *
  5.  * @package WordPress
  6.  */
  7.  
  8. require( ABSPATH . WPINC . '/option.php' );
  9.  
  10. /**
  11.  * Convert given date string into a different format.
  12.  *
  13.  * $format should be either a PHP date format string, e.g. 'U' for a Unix
  14.  * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT.
  15.  *
  16.  * If $translate is true then the given date and format string will
  17.  * be passed to date_i18n() for translation.
  18.  *
  19.  * @since 0.71
  20.  *
  21.  * @param string $format    Format of the date to return.
  22.  * @param string $date      Date string to convert.
  23.  * @param bool   $translate Whether the return date should be translated. Default true.
  24.  * @return string|int|bool Formatted date string or Unix timestamp. False if $date is empty.
  25.  */
  26. function mysql2date( $format, $date, $translate = true ) {
  27.     if ( empty( $date ) )
  28.         return false;
  29.  
  30.     if ( 'G' == $format )
  31.         return strtotime( $date . ' +0000' );
  32.  
  33.     $i = strtotime( $date );
  34.  
  35.     if ( 'U' == $format )
  36.         return $i;
  37.  
  38.     if ( $translate )
  39.         return date_i18n( $format, $i );
  40.     else
  41.         return date( $format, $i );
  42. }
  43.  
  44. /**
  45.  * Retrieve the current time based on specified type.
  46.  *
  47.  * The 'mysql' type will return the time in the format for MySQL DATETIME field.
  48.  * The 'timestamp' type will return the current timestamp.
  49.  * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
  50.  *
  51.  * If $gmt is set to either '1' or 'true', then both types will use GMT time.
  52.  * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
  53.  *
  54.  * @since 1.0.0
  55.  *
  56.  * @param string   $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date
  57.  *                       format string (e.g. 'Y-m-d').
  58.  * @param int|bool $gmt  Optional. Whether to use GMT timezone. Default false.
  59.  * @return int|string Integer if $type is 'timestamp', string otherwise.
  60.  */
  61. function current_time( $type, $gmt = 0 ) {
  62.     switch ( $type ) {
  63.         case 'mysql':
  64.             return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
  65.         case 'timestamp':
  66.             return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  67.         default:
  68.             return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
  69.     }
  70. }
  71.  
  72. /**
  73.  * Retrieve the date in localized format, based on timestamp.
  74.  *
  75.  * If the locale specifies the locale month and weekday, then the locale will
  76.  * take over the format for the date. If it isn't, then the date format string
  77.  * will be used instead.
  78.  *
  79.  * @since 0.71
  80.  *
  81.  * @global WP_Locale $wp_locale
  82.  *
  83.  * @param string   $dateformatstring Format to display the date.
  84.  * @param bool|int $unixtimestamp    Optional. Unix timestamp. Default false.
  85.  * @param bool     $gmt              Optional. Whether to use GMT timezone. Default false.
  86.  *
  87.  * @return string The date, translated if locale specifies it.
  88.  */
  89. function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
  90.     global $wp_locale;
  91.     $i = $unixtimestamp;
  92.  
  93.     if ( false === $i ) {
  94.         if ( ! $gmt )
  95.             $i = current_time( 'timestamp' );
  96.         else
  97.             $i = time();
  98.         // we should not let date() interfere with our
  99.         // specially computed timestamp
  100.         $gmt = true;
  101.     }
  102.  
  103.     /*
  104.      * Store original value for language with untypical grammars.
  105.      * See https://core.trac.wordpress.org/ticket/9396
  106.      */
  107.     $req_format = $dateformatstring;
  108.  
  109.     $datefunc = $gmt? 'gmdate' : 'date';
  110.  
  111.     if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
  112.         $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
  113.         $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
  114.         $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
  115.         $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
  116.         $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
  117.         $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
  118.         $dateformatstring = ' '.$dateformatstring;
  119.         $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
  120.         $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
  121.         $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
  122.         $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
  123.         $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
  124.         $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
  125.  
  126.         $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
  127.     }
  128.     $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
  129.     $timezone_formats_re = implode( '|', $timezone_formats );
  130.     if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
  131.         $timezone_string = get_option( 'timezone_string' );
  132.         if ( $timezone_string ) {
  133.             $timezone_object = timezone_open( $timezone_string );
  134.             $date_object = date_create( null, $timezone_object );
  135.             foreach ( $timezone_formats as $timezone_format ) {
  136.                 if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
  137.                     $formatted = date_format( $date_object, $timezone_format );
  138.                     $dateformatstring = ' '.$dateformatstring;
  139.                     $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
  140.                     $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
  141.                 }
  142.             }
  143.         }
  144.     }
  145.     $j = @$datefunc( $dateformatstring, $i );
  146.  
  147.     /**
  148.      * Filters the date formatted based on the locale.
  149.      *
  150.      * @since 2.8.0
  151.      *
  152.      * @param string $j          Formatted date string.
  153.      * @param string $req_format Format to display the date.
  154.      * @param int    $i          Unix timestamp.
  155.      * @param bool   $gmt        Whether to convert to GMT for time. Default false.
  156.      */
  157.     $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
  158.     return $j;
  159. }
  160.  
  161. /**
  162.  * Determines if the date should be declined.
  163.  *
  164.  * If the locale specifies that month names require a genitive case in certain
  165.  * formats (like 'j F Y'), the month name will be replaced with a correct form.
  166.  *
  167.  * @since 4.4.0
  168.  *
  169.  * @param string $date Formatted date string.
  170.  * @return string The date, declined if locale specifies it.
  171.  */
  172. function wp_maybe_decline_date( $date ) {
  173.     global $wp_locale;
  174.  
  175.     // i18n functions are not available in SHORTINIT mode
  176.     if ( ! function_exists( '_x' ) ) {
  177.         return $date;
  178.     }
  179.  
  180.     /* translators: If months in your language require a genitive case,
  181.      * translate this to 'on'. Do not translate into your own language.
  182.      */
  183.     if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
  184.         // Match a format like 'j F Y' or 'j. F'
  185.         if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
  186.             $months          = $wp_locale->month;
  187.             $months_genitive = $wp_locale->month_genitive;
  188.  
  189.             foreach ( $months as $key => $month ) {
  190.                 $months[ $key ] = '# ' . $month . '( |$)#u';
  191.             }
  192.  
  193.             foreach ( $months_genitive as $key => $month ) {
  194.                 $months_genitive[ $key ] = ' ' . $month . '$1';
  195.             }
  196.  
  197.             $date = preg_replace( $months, $months_genitive, $date );
  198.         }
  199.     }
  200.  
  201.     // Used for locale-specific rules
  202.     $locale = get_locale();
  203.  
  204.     if ( 'ca' === $locale ) {
  205.         // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
  206.         $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
  207.     }
  208.  
  209.     return $date;
  210. }
  211.  
  212. /**
  213.  * Convert float number to format based on the locale.
  214.  *
  215.  * @since 2.3.0
  216.  *
  217.  * @global WP_Locale $wp_locale
  218.  *
  219.  * @param float $number   The number to convert based on locale.
  220.  * @param int   $decimals Optional. Precision of the number of decimal places. Default 0.
  221.  * @return string Converted number in string format.
  222.  */
  223. function number_format_i18n( $number, $decimals = 0 ) {
  224.     global $wp_locale;
  225.  
  226.     if ( isset( $wp_locale ) ) {
  227.         $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
  228.     } else {
  229.         $formatted = number_format( $number, absint( $decimals ) );
  230.     }
  231.  
  232.     /**
  233.      * Filters the number formatted based on the locale.
  234.      *
  235.      * @since  2.8.0
  236.      *
  237.      * @param string $formatted Converted number in string format.
  238.      */
  239.     return apply_filters( 'number_format_i18n', $formatted );
  240. }
  241.  
  242. /**
  243.  * Convert number of bytes largest unit bytes will fit into.
  244.  *
  245.  * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
  246.  * number of bytes to human readable number by taking the number of that unit
  247.  * that the bytes will go into it. Supports TB value.
  248.  *
  249.  * Please note that integers in PHP are limited to 32 bits, unless they are on
  250.  * 64 bit architecture, then they have 64 bit size. If you need to place the
  251.  * larger size then what PHP integer type will hold, then use a string. It will
  252.  * be converted to a double, which should always have 64 bit length.
  253.  *
  254.  * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
  255.  *
  256.  * @since 2.3.0
  257.  *
  258.  * @param int|string $bytes    Number of bytes. Note max integer size for integers.
  259.  * @param int        $decimals Optional. Precision of number of decimal places. Default 0.
  260.  * @return string|false False on failure. Number string on success.
  261.  */
  262. function size_format( $bytes, $decimals = 0 ) {
  263.     $quant = array(
  264.         'TB' => TB_IN_BYTES,
  265.         'GB' => GB_IN_BYTES,
  266.         'MB' => MB_IN_BYTES,
  267.         'KB' => KB_IN_BYTES,
  268.         'B'  => 1,
  269.     );
  270.  
  271.     if ( 0 === $bytes ) {
  272.         return number_format_i18n( 0, $decimals ) . ' B';
  273.     }
  274.  
  275.     foreach ( $quant as $unit => $mag ) {
  276.         if ( doubleval( $bytes ) >= $mag ) {
  277.             return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
  278.         }
  279.     }
  280.  
  281.     return false;
  282. }
  283.  
  284. /**
  285.  * Get the week start and end from the datetime or date string from MySQL.
  286.  *
  287.  * @since 0.71
  288.  *
  289.  * @param string     $mysqlstring   Date or datetime field type from MySQL.
  290.  * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
  291.  * @return array Keys are 'start' and 'end'.
  292.  */
  293. function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
  294.     // MySQL string year.
  295.     $my = substr( $mysqlstring, 0, 4 );
  296.  
  297.     // MySQL string month.
  298.     $mm = substr( $mysqlstring, 8, 2 );
  299.  
  300.     // MySQL string day.
  301.     $md = substr( $mysqlstring, 5, 2 );
  302.  
  303.     // The timestamp for MySQL string day.
  304.     $day = mktime( 0, 0, 0, $md, $mm, $my );
  305.  
  306.     // The day of the week from the timestamp.
  307.     $weekday = date( 'w', $day );
  308.  
  309.     if ( !is_numeric($start_of_week) )
  310.         $start_of_week = get_option( 'start_of_week' );
  311.  
  312.     if ( $weekday < $start_of_week )
  313.         $weekday += 7;
  314.  
  315.     // The most recent week start day on or before $day.
  316.     $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
  317.  
  318.     // $start + 1 week - 1 second.
  319.     $end = $start + WEEK_IN_SECONDS - 1;
  320.     return compact( 'start', 'end' );
  321. }
  322.  
  323. /**
  324.  * Unserialize value only if it was serialized.
  325.  *
  326.  * @since 2.0.0
  327.  *
  328.  * @param string $original Maybe unserialized original, if is needed.
  329.  * @return mixed Unserialized data can be any type.
  330.  */
  331. function maybe_unserialize( $original ) {
  332.     if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
  333.         return @unserialize( $original );
  334.     return $original;
  335. }
  336.  
  337. /**
  338.  * Check value to find if it was serialized.
  339.  *
  340.  * If $data is not an string, then returned value will always be false.
  341.  * Serialized data is always a string.
  342.  *
  343.  * @since 2.0.5
  344.  *
  345.  * @param string $data   Value to check to see if was serialized.
  346.  * @param bool   $strict Optional. Whether to be strict about the end of the string. Default true.
  347.  * @return bool False if not serialized and true if it was.
  348.  */
  349. function is_serialized( $data, $strict = true ) {
  350.     // if it isn't a string, it isn't serialized.
  351.     if ( ! is_string( $data ) ) {
  352.         return false;
  353.     }
  354.     $data = trim( $data );
  355.     if ( 'N;' == $data ) {
  356.         return true;
  357.     }
  358.     if ( strlen( $data ) < 4 ) {
  359.         return false;
  360.     }
  361.     if ( ':' !== $data[1] ) {
  362.         return false;
  363.     }
  364.     if ( $strict ) {
  365.         $lastc = substr( $data, -1 );
  366.         if ( ';' !== $lastc && '}' !== $lastc ) {
  367.             return false;
  368.         }
  369.     } else {
  370.         $semicolon = strpos( $data, ';' );
  371.         $brace     = strpos( $data, '}' );
  372.         // Either ; or } must exist.
  373.         if ( false === $semicolon && false === $brace )
  374.             return false;
  375.         // But neither must be in the first X characters.
  376.         if ( false !== $semicolon && $semicolon < 3 )
  377.             return false;
  378.         if ( false !== $brace && $brace < 4 )
  379.             return false;
  380.     }
  381.     $token = $data[0];
  382.     switch ( $token ) {
  383.         case 's' :
  384.             if ( $strict ) {
  385.                 if ( '"' !== substr( $data, -2, 1 ) ) {
  386.                     return false;
  387.                 }
  388.             } elseif ( false === strpos( $data, '"' ) ) {
  389.                 return false;
  390.             }
  391.             // or else fall through
  392.         case 'a' :
  393.         case 'O' :
  394.             return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
  395.         case 'b' :
  396.         case 'i' :
  397.         case 'd' :
  398.             $end = $strict ? '$' : '';
  399.             return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
  400.     }
  401.     return false;
  402. }
  403.  
  404. /**
  405.  * Check whether serialized data is of string type.
  406.  *
  407.  * @since 2.0.5
  408.  *
  409.  * @param string $data Serialized data.
  410.  * @return bool False if not a serialized string, true if it is.
  411.  */
  412. function is_serialized_string( $data ) {
  413.     // if it isn't a string, it isn't a serialized string.
  414.     if ( ! is_string( $data ) ) {
  415.         return false;
  416.     }
  417.     $data = trim( $data );
  418.     if ( strlen( $data ) < 4 ) {
  419.         return false;
  420.     } elseif ( ':' !== $data[1] ) {
  421.         return false;
  422.     } elseif ( ';' !== substr( $data, -1 ) ) {
  423.         return false;
  424.     } elseif ( $data[0] !== 's' ) {
  425.         return false;
  426.     } elseif ( '"' !== substr( $data, -2, 1 ) ) {
  427.         return false;
  428.     } else {
  429.         return true;
  430.     }
  431. }
  432.  
  433. /**
  434.  * Serialize data, if needed.
  435.  *
  436.  * @since 2.0.5
  437.  *
  438.  * @param string|array|object $data Data that might be serialized.
  439.  * @return mixed A scalar data
  440.  */
  441. function maybe_serialize( $data ) {
  442.     if ( is_array( $data ) || is_object( $data ) )
  443.         return serialize( $data );
  444.  
  445.     // Double serialization is required for backward compatibility.
  446.     // See https://core.trac.wordpress.org/ticket/12930
  447.     // Also the world will end. See WP 3.6.1.
  448.     if ( is_serialized( $data, false ) )
  449.         return serialize( $data );
  450.  
  451.     return $data;
  452. }
  453.  
  454. /**
  455.  * Retrieve post title from XMLRPC XML.
  456.  *
  457.  * If the title element is not part of the XML, then the default post title from
  458.  * the $post_default_title will be used instead.
  459.  *
  460.  * @since 0.71
  461.  *
  462.  * @global string $post_default_title Default XML-RPC post title.
  463.  *
  464.  * @param string $content XMLRPC XML Request content
  465.  * @return string Post title
  466.  */
  467. function xmlrpc_getposttitle( $content ) {
  468.     global $post_default_title;
  469.     if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
  470.         $post_title = $matchtitle[1];
  471.     } else {
  472.         $post_title = $post_default_title;
  473.     }
  474.     return $post_title;
  475. }
  476.  
  477. /**
  478.  * Retrieve the post category or categories from XMLRPC XML.
  479.  *
  480.  * If the category element is not found, then the default post category will be
  481.  * used. The return type then would be what $post_default_category. If the
  482.  * category is found, then it will always be an array.
  483.  *
  484.  * @since 0.71
  485.  *
  486.  * @global string $post_default_category Default XML-RPC post category.
  487.  *
  488.  * @param string $content XMLRPC XML Request content
  489.  * @return string|array List of categories or category name.
  490.  */
  491. function xmlrpc_getpostcategory( $content ) {
  492.     global $post_default_category;
  493.     if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
  494.         $post_category = trim( $matchcat[1], ',' );
  495.         $post_category = explode( ',', $post_category );
  496.     } else {
  497.         $post_category = $post_default_category;
  498.     }
  499.     return $post_category;
  500. }
  501.  
  502. /**
  503.  * XMLRPC XML content without title and category elements.
  504.  *
  505.  * @since 0.71
  506.  *
  507.  * @param string $content XML-RPC XML Request content.
  508.  * @return string XMLRPC XML Request content without title and category elements.
  509.  */
  510. function xmlrpc_removepostdata( $content ) {
  511.     $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
  512.     $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
  513.     $content = trim( $content );
  514.     return $content;
  515. }
  516.  
  517. /**
  518.  * Use RegEx to extract URLs from arbitrary content.
  519.  *
  520.  * @since 3.7.0
  521.  *
  522.  * @param string $content Content to extract URLs from.
  523.  * @return array URLs found in passed string.
  524.  */
  525. function wp_extract_urls( $content ) {
  526.     preg_match_all(
  527.         "#([\"']?)("
  528.             . "(?:([\w-]+:)?//?)"
  529.             . "[^\s()<>]+"
  530.             . "[.]"
  531.             . "(?:"
  532.                 . "\([\w\d]+\)|"
  533.                 . "(?:"
  534.                     . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
  535.                     . "(?:[:]\d+)?/?"
  536.                 . ")+"
  537.             . ")"
  538.         . ")\\1#",
  539.         $content,
  540.         $post_links
  541.     );
  542.  
  543.     $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
  544.  
  545.     return array_values( $post_links );
  546. }
  547.  
  548. /**
  549.  * Check content for video and audio links to add as enclosures.
  550.  *
  551.  * Will not add enclosures that have already been added and will
  552.  * remove enclosures that are no longer in the post. This is called as
  553.  * pingbacks and trackbacks.
  554.  *
  555.  * @since 1.5.0
  556.  *
  557.  * @global wpdb $wpdb WordPress database abstraction object.
  558.  *
  559.  * @param string $content Post Content.
  560.  * @param int    $post_ID Post ID.
  561.  */
  562. function do_enclose( $content, $post_ID ) {
  563.     global $wpdb;
  564.  
  565.     //TODO: Tidy this ghetto code up and make the debug code optional
  566.     include_once( ABSPATH . WPINC . '/class-IXR.php' );
  567.  
  568.     $post_links = array();
  569.  
  570.     $pung = get_enclosed( $post_ID );
  571.  
  572.     $post_links_temp = wp_extract_urls( $content );
  573.  
  574.     foreach ( $pung as $link_test ) {
  575.         if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
  576.             $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 ) . '%') );
  577.             foreach ( $mids as $mid )
  578.                 delete_metadata_by_mid( 'post', $mid );
  579.         }
  580.     }
  581.  
  582.     foreach ( (array) $post_links_temp as $link_test ) {
  583.         if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
  584.             $test = @parse_url( $link_test );
  585.             if ( false === $test )
  586.                 continue;
  587.             if ( isset( $test['query'] ) )
  588.                 $post_links[] = $link_test;
  589.             elseif ( isset($test['path']) && ( $test['path'] != '/' ) &&  ($test['path'] != '' ) )
  590.                 $post_links[] = $link_test;
  591.         }
  592.     }
  593.  
  594.     /**
  595.      * Filters the list of enclosure links before querying the database.
  596.      *
  597.      * Allows for the addition and/or removal of potential enclosures to save
  598.      * to postmeta before checking the database for existing enclosures.
  599.      *
  600.      * @since 4.4.0
  601.      *
  602.      * @param array $post_links An array of enclosure links.
  603.      * @param int   $post_ID    Post ID.
  604.      */
  605.     $post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
  606.  
  607.     foreach ( (array) $post_links as $url ) {
  608.         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 ) . '%' ) ) ) {
  609.  
  610.             if ( $headers = wp_get_http_headers( $url) ) {
  611.                 $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
  612.                 $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
  613.                 $allowed_types = array( 'video', 'audio' );
  614.  
  615.                 // Check to see if we can figure out the mime type from
  616.                 // the extension
  617.                 $url_parts = @parse_url( $url );
  618.                 if ( false !== $url_parts ) {
  619.                     $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
  620.                     if ( !empty( $extension ) ) {
  621.                         foreach ( wp_get_mime_types() as $exts => $mime ) {
  622.                             if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
  623.                                 $type = $mime;
  624.                                 break;
  625.                             }
  626.                         }
  627.                     }
  628.                 }
  629.  
  630.                 if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
  631.                     add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
  632.                 }
  633.             }
  634.         }
  635.     }
  636. }
  637.  
  638. /**
  639.  * Retrieve HTTP Headers from URL.
  640.  *
  641.  * @since 1.5.1
  642.  *
  643.  * @param string $url        URL to retrieve HTTP headers from.
  644.  * @param bool   $deprecated Not Used.
  645.  * @return bool|string False on failure, headers on success.
  646.  */
  647. function wp_get_http_headers( $url, $deprecated = false ) {
  648.     if ( !empty( $deprecated ) )
  649.         _deprecated_argument( __FUNCTION__, '2.7.0' );
  650.  
  651.     $response = wp_safe_remote_head( $url );
  652.  
  653.     if ( is_wp_error( $response ) )
  654.         return false;
  655.  
  656.     return wp_remote_retrieve_headers( $response );
  657. }
  658.  
  659. /**
  660.  * Whether the publish date of the current post in the loop is different from the
  661.  * publish date of the previous post in the loop.
  662.  *
  663.  * @since 0.71
  664.  *
  665.  * @global string $currentday  The day of the current post in the loop.
  666.  * @global string $previousday The day of the previous post in the loop.
  667.  *
  668.  * @return int 1 when new day, 0 if not a new day.
  669.  */
  670. function is_new_day() {
  671.     global $currentday, $previousday;
  672.     if ( $currentday != $previousday )
  673.         return 1;
  674.     else
  675.         return 0;
  676. }
  677.  
  678. /**
  679.  * Build URL query based on an associative and, or indexed array.
  680.  *
  681.  * This is a convenient function for easily building url queries. It sets the
  682.  * separator to '&' and uses _http_build_query() function.
  683.  *
  684.  * @since 2.3.0
  685.  *
  686.  * @see _http_build_query() Used to build the query
  687.  * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
  688.  *       http_build_query() does.
  689.  *
  690.  * @param array $data URL-encode key/value pairs.
  691.  * @return string URL-encoded string.
  692.  */
  693. function build_query( $data ) {
  694.     return _http_build_query( $data, null, '&', '', false );
  695. }
  696.  
  697. /**
  698.  * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
  699.  *
  700.  * @since 3.2.0
  701.  * @access private
  702.  *
  703.  * @see https://secure.php.net/manual/en/function.http-build-query.php
  704.  *
  705.  * @param array|object  $data       An array or object of data. Converted to array.
  706.  * @param string        $prefix     Optional. Numeric index. If set, start parameter numbering with it.
  707.  *                                  Default null.
  708.  * @param string        $sep        Optional. Argument separator; defaults to 'arg_separator.output'.
  709.  *                                  Default null.
  710.  * @param string        $key        Optional. Used to prefix key name. Default empty.
  711.  * @param bool          $urlencode  Optional. Whether to use urlencode() in the result. Default true.
  712.  *
  713.  * @return string The query string.
  714.  */
  715. function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
  716.     $ret = array();
  717.  
  718.     foreach ( (array) $data as $k => $v ) {
  719.         if ( $urlencode)
  720.             $k = urlencode($k);
  721.         if ( is_int($k) && $prefix != null )
  722.             $k = $prefix.$k;
  723.         if ( !empty($key) )
  724.             $k = $key . '%5B' . $k . '%5D';
  725.         if ( $v === null )
  726.             continue;
  727.         elseif ( $v === false )
  728.             $v = '0';
  729.  
  730.         if ( is_array($v) || is_object($v) )
  731.             array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
  732.         elseif ( $urlencode )
  733.             array_push($ret, $k.'='.urlencode($v));
  734.         else
  735.             array_push($ret, $k.'='.$v);
  736.     }
  737.  
  738.     if ( null === $sep )
  739.         $sep = ini_get('arg_separator.output');
  740.  
  741.     return implode($sep, $ret);
  742. }
  743.  
  744. /**
  745.  * Retrieves a modified URL query string.
  746.  *
  747.  * You can rebuild the URL and append query variables to the URL query by using this function.
  748.  * There are two ways to use this function; either a single key and value, or an associative array.
  749.  *
  750.  * Using a single key and value:
  751.  *
  752.  *     add_query_arg( 'key', 'value', 'http://example.com' );
  753.  *
  754.  * Using an associative array:
  755.  *
  756.  *     add_query_arg( array(
  757.  *         'key1' => 'value1',
  758.  *         'key2' => 'value2',
  759.  *     ), 'http://example.com' );
  760.  *
  761.  * Omitting the URL from either use results in the current URL being used
  762.  * (the value of `$_SERVER['REQUEST_URI']`).
  763.  *
  764.  * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
  765.  *
  766.  * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
  767.  *
  768.  * Important: The return value of add_query_arg() is not escaped by default. Output should be
  769.  * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
  770.  * (XSS) attacks.
  771.  *
  772.  * @since 1.5.0
  773.  *
  774.  * @param string|array $key   Either a query variable key, or an associative array of query variables.
  775.  * @param string       $value Optional. Either a query variable value, or a URL to act upon.
  776.  * @param string       $url   Optional. A URL to act upon.
  777.  * @return string New URL query string (unescaped).
  778.  */
  779. function add_query_arg() {
  780.     $args = func_get_args();
  781.     if ( is_array( $args[0] ) ) {
  782.         if ( count( $args ) < 2 || false === $args[1] )
  783.             $uri = $_SERVER['REQUEST_URI'];
  784.         else
  785.             $uri = $args[1];
  786.     } else {
  787.         if ( count( $args ) < 3 || false === $args[2] )
  788.             $uri = $_SERVER['REQUEST_URI'];
  789.         else
  790.             $uri = $args[2];
  791.     }
  792.  
  793.     if ( $frag = strstr( $uri, '#' ) )
  794.         $uri = substr( $uri, 0, -strlen( $frag ) );
  795.     else
  796.         $frag = '';
  797.  
  798.     if ( 0 === stripos( $uri, 'http://' ) ) {
  799.         $protocol = 'http://';
  800.         $uri = substr( $uri, 7 );
  801.     } elseif ( 0 === stripos( $uri, 'https://' ) ) {
  802.         $protocol = 'https://';
  803.         $uri = substr( $uri, 8 );
  804.     } else {
  805.         $protocol = '';
  806.     }
  807.  
  808.     if ( strpos( $uri, '?' ) !== false ) {
  809.         list( $base, $query ) = explode( '?', $uri, 2 );
  810.         $base .= '?';
  811.     } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
  812.         $base = $uri . '?';
  813.         $query = '';
  814.     } else {
  815.         $base = '';
  816.         $query = $uri;
  817.     }
  818.  
  819.     wp_parse_str( $query, $qs );
  820.     $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
  821.     if ( is_array( $args[0] ) ) {
  822.         foreach ( $args[0] as $k => $v ) {
  823.             $qs[ $k ] = $v;
  824.         }
  825.     } else {
  826.         $qs[ $args[0] ] = $args[1];
  827.     }
  828.  
  829.     foreach ( $qs as $k => $v ) {
  830.         if ( $v === false )
  831.             unset( $qs[$k] );
  832.     }
  833.  
  834.     $ret = build_query( $qs );
  835.     $ret = trim( $ret, '?' );
  836.     $ret = preg_replace( '#=(&|$)#', '$1', $ret );
  837.     $ret = $protocol . $base . $ret . $frag;
  838.     $ret = rtrim( $ret, '?' );
  839.     return $ret;
  840. }
  841.  
  842. /**
  843.  * Removes an item or items from a query string.
  844.  *
  845.  * @since 1.5.0
  846.  *
  847.  * @param string|array $key   Query key or keys to remove.
  848.  * @param bool|string  $query Optional. When false uses the current URL. Default false.
  849.  * @return string New URL query string.
  850.  */
  851. function remove_query_arg( $key, $query = false ) {
  852.     if ( is_array( $key ) ) { // removing multiple keys
  853.         foreach ( $key as $k )
  854.             $query = add_query_arg( $k, false, $query );
  855.         return $query;
  856.     }
  857.     return add_query_arg( $key, false, $query );
  858. }
  859.  
  860. /**
  861.  * Returns an array of single-use query variable names that can be removed from a URL.
  862.  *
  863.  * @since 4.4.0
  864.  *
  865.  * @return array An array of parameters to remove from the URL.
  866.  */
  867. function wp_removable_query_args() {
  868.     $removable_query_args = array(
  869.         'activate',
  870.         'activated',
  871.         'approved',
  872.         'deactivate',
  873.         'deleted',
  874.         'disabled',
  875.         'enabled',
  876.         'error',
  877.         'hotkeys_highlight_first',
  878.         'hotkeys_highlight_last',
  879.         'locked',
  880.         'message',
  881.         'same',
  882.         'saved',
  883.         'settings-updated',
  884.         'skipped',
  885.         'spammed',
  886.         'trashed',
  887.         'unspammed',
  888.         'untrashed',
  889.         'update',
  890.         'updated',
  891.         'wp-post-new-reload',
  892.     );
  893.  
  894.     /**
  895.      * Filters the list of query variables to remove.
  896.      *
  897.      * @since 4.2.0
  898.      *
  899.      * @param array $removable_query_args An array of query variables to remove from a URL.
  900.      */
  901.     return apply_filters( 'removable_query_args', $removable_query_args );
  902. }
  903.  
  904. /**
  905.  * Walks the array while sanitizing the contents.
  906.  *
  907.  * @since 0.71
  908.  *
  909.  * @param array $array Array to walk while sanitizing contents.
  910.  * @return array Sanitized $array.
  911.  */
  912. function add_magic_quotes( $array ) {
  913.     foreach ( (array) $array as $k => $v ) {
  914.         if ( is_array( $v ) ) {
  915.             $array[$k] = add_magic_quotes( $v );
  916.         } else {
  917.             $array[$k] = addslashes( $v );
  918.         }
  919.     }
  920.     return $array;
  921. }
  922.  
  923. /**
  924.  * HTTP request for URI to retrieve content.
  925.  *
  926.  * @since 1.5.1
  927.  *
  928.  * @see wp_safe_remote_get()
  929.  *
  930.  * @param string $uri URI/URL of web page to retrieve.
  931.  * @return false|string HTTP content. False on failure.
  932.  */
  933. function wp_remote_fopen( $uri ) {
  934.     $parsed_url = @parse_url( $uri );
  935.  
  936.     if ( !$parsed_url || !is_array( $parsed_url ) )
  937.         return false;
  938.  
  939.     $options = array();
  940.     $options['timeout'] = 10;
  941.  
  942.     $response = wp_safe_remote_get( $uri, $options );
  943.  
  944.     if ( is_wp_error( $response ) )
  945.         return false;
  946.  
  947.     return wp_remote_retrieve_body( $response );
  948. }
  949.  
  950. /**
  951.  * Set up the WordPress query.
  952.  *
  953.  * @since 2.0.0
  954.  *
  955.  * @global WP       $wp_locale
  956.  * @global WP_Query $wp_query
  957.  * @global WP_Query $wp_the_query
  958.  *
  959.  * @param string|array $query_vars Default WP_Query arguments.
  960.  */
  961. function wp( $query_vars = '' ) {
  962.     global $wp, $wp_query, $wp_the_query;
  963.     $wp->main( $query_vars );
  964.  
  965.     if ( !isset($wp_the_query) )
  966.         $wp_the_query = $wp_query;
  967. }
  968.  
  969. /**
  970.  * Retrieve the description for the HTTP status.
  971.  *
  972.  * @since 2.3.0
  973.  *
  974.  * @global array $wp_header_to_desc
  975.  *
  976.  * @param int $code HTTP status code.
  977.  * @return string Empty string if not found, or description if found.
  978.  */
  979. function get_status_header_desc( $code ) {
  980.     global $wp_header_to_desc;
  981.  
  982.     $code = absint( $code );
  983.  
  984.     if ( !isset( $wp_header_to_desc ) ) {
  985.         $wp_header_to_desc = array(
  986.             100 => 'Continue',
  987.             101 => 'Switching Protocols',
  988.             102 => 'Processing',
  989.  
  990.             200 => 'OK',
  991.             201 => 'Created',
  992.             202 => 'Accepted',
  993.             203 => 'Non-Authoritative Information',
  994.             204 => 'No Content',
  995.             205 => 'Reset Content',
  996.             206 => 'Partial Content',
  997.             207 => 'Multi-Status',
  998.             226 => 'IM Used',
  999.  
  1000.             300 => 'Multiple Choices',
  1001.             301 => 'Moved Permanently',
  1002.             302 => 'Found',
  1003.             303 => 'See Other',
  1004.             304 => 'Not Modified',
  1005.             305 => 'Use Proxy',
  1006.             306 => 'Reserved',
  1007.             307 => 'Temporary Redirect',
  1008.             308 => 'Permanent Redirect',
  1009.  
  1010.             400 => 'Bad Request',
  1011.             401 => 'Unauthorized',
  1012.             402 => 'Payment Required',
  1013.             403 => 'Forbidden',
  1014.             404 => 'Not Found',
  1015.             405 => 'Method Not Allowed',
  1016.             406 => 'Not Acceptable',
  1017.             407 => 'Proxy Authentication Required',
  1018.             408 => 'Request Timeout',
  1019.             409 => 'Conflict',
  1020.             410 => 'Gone',
  1021.             411 => 'Length Required',
  1022.             412 => 'Precondition Failed',
  1023.             413 => 'Request Entity Too Large',
  1024.             414 => 'Request-URI Too Long',
  1025.             415 => 'Unsupported Media Type',
  1026.             416 => 'Requested Range Not Satisfiable',
  1027.             417 => 'Expectation Failed',
  1028.             418 => 'I\'m a teapot',
  1029.             421 => 'Misdirected Request',
  1030.             422 => 'Unprocessable Entity',
  1031.             423 => 'Locked',
  1032.             424 => 'Failed Dependency',
  1033.             426 => 'Upgrade Required',
  1034.             428 => 'Precondition Required',
  1035.             429 => 'Too Many Requests',
  1036.             431 => 'Request Header Fields Too Large',
  1037.             451 => 'Unavailable For Legal Reasons',
  1038.  
  1039.             500 => 'Internal Server Error',
  1040.             501 => 'Not Implemented',
  1041.             502 => 'Bad Gateway',
  1042.             503 => 'Service Unavailable',
  1043.             504 => 'Gateway Timeout',
  1044.             505 => 'HTTP Version Not Supported',
  1045.             506 => 'Variant Also Negotiates',
  1046.             507 => 'Insufficient Storage',
  1047.             510 => 'Not Extended',
  1048.             511 => 'Network Authentication Required',
  1049.         );
  1050.     }
  1051.  
  1052.     if ( isset( $wp_header_to_desc[$code] ) )
  1053.         return $wp_header_to_desc[$code];
  1054.     else
  1055.         return '';
  1056. }
  1057.  
  1058. /**
  1059.  * Set HTTP status header.
  1060.  *
  1061.  * @since 2.0.0
  1062.  * @since 4.4.0 Added the `$description` parameter.
  1063.  *
  1064.  * @see get_status_header_desc()
  1065.  *
  1066.  * @param int    $code        HTTP status code.
  1067.  * @param string $description Optional. A custom description for the HTTP status.
  1068.  */
  1069. function status_header( $code, $description = '' ) {
  1070.     if ( ! $description ) {
  1071.         $description = get_status_header_desc( $code );
  1072.     }
  1073.  
  1074.     if ( empty( $description ) ) {
  1075.         return;
  1076.     }
  1077.  
  1078.     $protocol = wp_get_server_protocol();
  1079.     $status_header = "$protocol $code $description";
  1080.     if ( function_exists( 'apply_filters' ) )
  1081.  
  1082.         /**
  1083.          * Filters an HTTP status header.
  1084.          *
  1085.          * @since 2.2.0
  1086.          *
  1087.          * @param string $status_header HTTP status header.
  1088.          * @param int    $code          HTTP status code.
  1089.          * @param string $description   Description for the status code.
  1090.          * @param string $protocol      Server protocol.
  1091.          */
  1092.         $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
  1093.  
  1094.     @header( $status_header, true, $code );
  1095. }
  1096.  
  1097. /**
  1098.  * Get the header information to prevent caching.
  1099.  *
  1100.  * The several different headers cover the different ways cache prevention
  1101.  * is handled by different browsers
  1102.  *
  1103.  * @since 2.8.0
  1104.  *
  1105.  * @return array The associative array of header names and field values.
  1106.  */
  1107. function wp_get_nocache_headers() {
  1108.     $headers = array(
  1109.         'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
  1110.         'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
  1111.     );
  1112.  
  1113.     if ( function_exists('apply_filters') ) {
  1114.         /**
  1115.          * Filters the cache-controlling headers.
  1116.          *
  1117.          * @since 2.8.0
  1118.          *
  1119.          * @see wp_get_nocache_headers()
  1120.          *
  1121.          * @param array $headers {
  1122.          *     Header names and field values.
  1123.          *
  1124.          *     @type string $Expires       Expires header.
  1125.          *     @type string $Cache-Control Cache-Control header.
  1126.          * }
  1127.          */
  1128.         $headers = (array) apply_filters( 'nocache_headers', $headers );
  1129.     }
  1130.     $headers['Last-Modified'] = false;
  1131.     return $headers;
  1132. }
  1133.  
  1134. /**
  1135.  * Set the headers to prevent caching for the different browsers.
  1136.  *
  1137.  * Different browsers support different nocache headers, so several
  1138.  * headers must be sent so that all of them get the point that no
  1139.  * caching should occur.
  1140.  *
  1141.  * @since 2.0.0
  1142.  *
  1143.  * @see wp_get_nocache_headers()
  1144.  */
  1145. function nocache_headers() {
  1146.     $headers = wp_get_nocache_headers();
  1147.  
  1148.     unset( $headers['Last-Modified'] );
  1149.  
  1150.     // In PHP 5.3+, make sure we are not sending a Last-Modified header.
  1151.     if ( function_exists( 'header_remove' ) ) {
  1152.         @header_remove( 'Last-Modified' );
  1153.     } else {
  1154.         // In PHP 5.2, send an empty Last-Modified header, but only as a
  1155.         // last resort to override a header already sent. #WP23021
  1156.         foreach ( headers_list() as $header ) {
  1157.             if ( 0 === stripos( $header, 'Last-Modified' ) ) {
  1158.                 $headers['Last-Modified'] = '';
  1159.                 break;
  1160.             }
  1161.         }
  1162.     }
  1163.  
  1164.     foreach ( $headers as $name => $field_value )
  1165.         @header("{$name}: {$field_value}");
  1166. }
  1167.  
  1168. /**
  1169.  * Set the headers for caching for 10 days with JavaScript content type.
  1170.  *
  1171.  * @since 2.1.0
  1172.  */
  1173. function cache_javascript_headers() {
  1174.     $expiresOffset = 10 * DAY_IN_SECONDS;
  1175.  
  1176.     header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
  1177.     header( "Vary: Accept-Encoding" ); // Handle proxies
  1178.     header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
  1179. }
  1180.  
  1181. /**
  1182.  * Retrieve the number of database queries during the WordPress execution.
  1183.  *
  1184.  * @since 2.0.0
  1185.  *
  1186.  * @global wpdb $wpdb WordPress database abstraction object.
  1187.  *
  1188.  * @return int Number of database queries.
  1189.  */
  1190. function get_num_queries() {
  1191.     global $wpdb;
  1192.     return $wpdb->num_queries;
  1193. }
  1194.  
  1195. /**
  1196.  * Whether input is yes or no.
  1197.  *
  1198.  * Must be 'y' to be true.
  1199.  *
  1200.  * @since 1.0.0
  1201.  *
  1202.  * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
  1203.  * @return bool True if yes, false on anything else.
  1204.  */
  1205. function bool_from_yn( $yn ) {
  1206.     return ( strtolower( $yn ) == 'y' );
  1207. }
  1208.  
  1209. /**
  1210.  * Load the feed template from the use of an action hook.
  1211.  *
  1212.  * If the feed action does not have a hook, then the function will die with a
  1213.  * message telling the visitor that the feed is not valid.
  1214.  *
  1215.  * It is better to only have one hook for each feed.
  1216.  *
  1217.  * @since 2.1.0
  1218.  *
  1219.  * @global WP_Query $wp_query Used to tell if the use a comment feed.
  1220.  */
  1221. function do_feed() {
  1222.     global $wp_query;
  1223.  
  1224.     $feed = get_query_var( 'feed' );
  1225.  
  1226.     // Remove the pad, if present.
  1227.     $feed = preg_replace( '/^_+/', '', $feed );
  1228.  
  1229.     if ( $feed == '' || $feed == 'feed' )
  1230.         $feed = get_default_feed();
  1231.  
  1232.     if ( ! has_action( "do_feed_{$feed}" ) ) {
  1233.         wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
  1234.     }
  1235.  
  1236.     /**
  1237.      * Fires once the given feed is loaded.
  1238.      *
  1239.      * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
  1240.      * Possible values include: 'rdf', 'rss', 'rss2', and 'atom'.
  1241.      *
  1242.      * @since 2.1.0
  1243.      * @since 4.4.0 The `$feed` parameter was added.
  1244.      *
  1245.      * @param bool   $is_comment_feed Whether the feed is a comment feed.
  1246.      * @param string $feed            The feed name.
  1247.      */
  1248.     do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
  1249. }
  1250.  
  1251. /**
  1252.  * Load the RDF RSS 0.91 Feed template.
  1253.  *
  1254.  * @since 2.1.0
  1255.  *
  1256.  * @see load_template()
  1257.  */
  1258. function do_feed_rdf() {
  1259.     load_template( ABSPATH . WPINC . '/feed-rdf.php' );
  1260. }
  1261.  
  1262. /**
  1263.  * Load the RSS 1.0 Feed Template.
  1264.  *
  1265.  * @since 2.1.0
  1266.  *
  1267.  * @see load_template()
  1268.  */
  1269. function do_feed_rss() {
  1270.     load_template( ABSPATH . WPINC . '/feed-rss.php' );
  1271. }
  1272.  
  1273. /**
  1274.  * Load either the RSS2 comment feed or the RSS2 posts feed.
  1275.  *
  1276.  * @since 2.1.0
  1277.  *
  1278.  * @see load_template()
  1279.  *
  1280.  * @param bool $for_comments True for the comment feed, false for normal feed.
  1281.  */
  1282. function do_feed_rss2( $for_comments ) {
  1283.     if ( $for_comments )
  1284.         load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
  1285.     else
  1286.         load_template( ABSPATH . WPINC . '/feed-rss2.php' );
  1287. }
  1288.  
  1289. /**
  1290.  * Load either Atom comment feed or Atom posts feed.
  1291.  *
  1292.  * @since 2.1.0
  1293.  *
  1294.  * @see load_template()
  1295.  *
  1296.  * @param bool $for_comments True for the comment feed, false for normal feed.
  1297.  */
  1298. function do_feed_atom( $for_comments ) {
  1299.     if ($for_comments)
  1300.         load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
  1301.     else
  1302.         load_template( ABSPATH . WPINC . '/feed-atom.php' );
  1303. }
  1304.  
  1305. /**
  1306.  * Display the robots.txt file content.
  1307.  *
  1308.  * The echo content should be with usage of the permalinks or for creating the
  1309.  * robots.txt file.
  1310.  *
  1311.  * @since 2.1.0
  1312.  */
  1313. function do_robots() {
  1314.     header( 'Content-Type: text/plain; charset=utf-8' );
  1315.  
  1316.     /**
  1317.      * Fires when displaying the robots.txt file.
  1318.      *
  1319.      * @since 2.1.0
  1320.      */
  1321.     do_action( 'do_robotstxt' );
  1322.  
  1323.     $output = "User-agent: *\n";
  1324.     $public = get_option( 'blog_public' );
  1325.     if ( '0' == $public ) {
  1326.         $output .= "Disallow: /\n";
  1327.     } else {
  1328.         $site_url = parse_url( site_url() );
  1329.         $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
  1330.         $output .= "Disallow: $path/wp-admin/\n";
  1331.         $output .= "Allow: $path/wp-admin/admin-ajax.php\n";
  1332.     }
  1333.  
  1334.     /**
  1335.      * Filters the robots.txt output.
  1336.      *
  1337.      * @since 3.0.0
  1338.      *
  1339.      * @param string $output Robots.txt output.
  1340.      * @param bool   $public Whether the site is considered "public".
  1341.      */
  1342.     echo apply_filters( 'robots_txt', $output, $public );
  1343. }
  1344.  
  1345. /**
  1346.  * Test whether WordPress is already installed.
  1347.  *
  1348.  * The cache will be checked first. If you have a cache plugin, which saves
  1349.  * the cache values, then this will work. If you use the default WordPress
  1350.  * cache, and the database goes away, then you might have problems.
  1351.  *
  1352.  * Checks for the 'siteurl' option for whether WordPress is installed.
  1353.  *
  1354.  * @since 2.1.0
  1355.  *
  1356.  * @global wpdb $wpdb WordPress database abstraction object.
  1357.  *
  1358.  * @return bool Whether the site is already installed.
  1359.  */
  1360. function is_blog_installed() {
  1361.     global $wpdb;
  1362.  
  1363.     /*
  1364.      * Check cache first. If options table goes away and we have true
  1365.      * cached, oh well.
  1366.      */
  1367.     if ( wp_cache_get( 'is_blog_installed' ) )
  1368.         return true;
  1369.  
  1370.     $suppress = $wpdb->suppress_errors();
  1371.     if ( ! wp_installing() ) {
  1372.         $alloptions = wp_load_alloptions();
  1373.     }
  1374.     // If siteurl is not set to autoload, check it specifically
  1375.     if ( !isset( $alloptions['siteurl'] ) )
  1376.         $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
  1377.     else
  1378.         $installed = $alloptions['siteurl'];
  1379.     $wpdb->suppress_errors( $suppress );
  1380.  
  1381.     $installed = !empty( $installed );
  1382.     wp_cache_set( 'is_blog_installed', $installed );
  1383.  
  1384.     if ( $installed )
  1385.         return true;
  1386.  
  1387.     // If visiting repair.php, return true and let it take over.
  1388.     if ( defined( 'WP_REPAIRING' ) )
  1389.         return true;
  1390.  
  1391.     $suppress = $wpdb->suppress_errors();
  1392.  
  1393.     /*
  1394.      * Loop over the WP tables. If none exist, then scratch install is allowed.
  1395.      * If one or more exist, suggest table repair since we got here because the
  1396.      * options table could not be accessed.
  1397.      */
  1398.     $wp_tables = $wpdb->tables();
  1399.     foreach ( $wp_tables as $table ) {
  1400.         // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
  1401.         if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
  1402.             continue;
  1403.         if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
  1404.             continue;
  1405.  
  1406.         if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
  1407.             continue;
  1408.  
  1409.         // One or more tables exist. We are insane.
  1410.  
  1411.         wp_load_translations_early();
  1412.  
  1413.         // Die with a DB error.
  1414.         $wpdb->error = sprintf( __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ), 'maint/repair.php?referrer=is_blog_installed' );
  1415.         dead_db();
  1416.     }
  1417.  
  1418.     $wpdb->suppress_errors( $suppress );
  1419.  
  1420.     wp_cache_set( 'is_blog_installed', false );
  1421.  
  1422.     return false;
  1423. }
  1424.  
  1425. /**
  1426.  * Retrieve URL with nonce added to URL query.
  1427.  *
  1428.  * @since 2.0.4
  1429.  *
  1430.  * @param string     $actionurl URL to add nonce action.
  1431.  * @param int|string $action    Optional. Nonce action name. Default -1.
  1432.  * @param string     $name      Optional. Nonce name. Default '_wpnonce'.
  1433.  * @return string Escaped URL with nonce action added.
  1434.  */
  1435. function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
  1436.     $actionurl = str_replace( '&', '&', $actionurl );
  1437.     return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
  1438. }
  1439.  
  1440. /**
  1441.  * Retrieve or display nonce hidden field for forms.
  1442.  *
  1443.  * The nonce field is used to validate that the contents of the form came from
  1444.  * the location on the current site and not somewhere else. The nonce does not
  1445.  * offer absolute protection, but should protect against most cases. It is very
  1446.  * important to use nonce field in forms.
  1447.  *
  1448.  * The $action and $name are optional, but if you want to have better security,
  1449.  * it is strongly suggested to set those two parameters. It is easier to just
  1450.  * call the function without any parameters, because validation of the nonce
  1451.  * doesn't require any parameters, but since crackers know what the default is
  1452.  * it won't be difficult for them to find a way around your nonce and cause
  1453.  * damage.
  1454.  *
  1455.  * The input name will be whatever $name value you gave. The input value will be
  1456.  * the nonce creation value.
  1457.  *
  1458.  * @since 2.0.4
  1459.  *
  1460.  * @param int|string $action  Optional. Action name. Default -1.
  1461.  * @param string     $name    Optional. Nonce name. Default '_wpnonce'.
  1462.  * @param bool       $referer Optional. Whether to set the referer field for validation. Default true.
  1463.  * @param bool       $echo    Optional. Whether to display or return hidden form field. Default true.
  1464.  * @return string Nonce field HTML markup.
  1465.  */
  1466. function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
  1467.     $name = esc_attr( $name );
  1468.     $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
  1469.  
  1470.     if ( $referer )
  1471.         $nonce_field .= wp_referer_field( false );
  1472.  
  1473.     if ( $echo )
  1474.         echo $nonce_field;
  1475.  
  1476.     return $nonce_field;
  1477. }
  1478.  
  1479. /**
  1480.  * Retrieve or display referer hidden field for forms.
  1481.  *
  1482.  * The referer link is the current Request URI from the server super global. The
  1483.  * input name is '_wp_http_referer', in case you wanted to check manually.
  1484.  *
  1485.  * @since 2.0.4
  1486.  *
  1487.  * @param bool $echo Optional. Whether to echo or return the referer field. Default true.
  1488.  * @return string Referer field HTML markup.
  1489.  */
  1490. function wp_referer_field( $echo = true ) {
  1491.     $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
  1492.  
  1493.     if ( $echo )
  1494.         echo $referer_field;
  1495.     return $referer_field;
  1496. }
  1497.  
  1498. /**
  1499.  * Retrieve or display original referer hidden field for forms.
  1500.  *
  1501.  * The input name is '_wp_original_http_referer' and will be either the same
  1502.  * value of wp_referer_field(), if that was posted already or it will be the
  1503.  * current page, if it doesn't exist.
  1504.  *
  1505.  * @since 2.0.4
  1506.  *
  1507.  * @param bool   $echo         Optional. Whether to echo the original http referer. Default true.
  1508.  * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
  1509.  *                             Default 'current'.
  1510.  * @return string Original referer field.
  1511.  */
  1512. function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
  1513.     if ( ! $ref = wp_get_original_referer() ) {
  1514.         $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
  1515.     }
  1516.     $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
  1517.     if ( $echo )
  1518.         echo $orig_referer_field;
  1519.     return $orig_referer_field;
  1520. }
  1521.  
  1522. /**
  1523.  * Retrieve referer from '_wp_http_referer' or HTTP referer.
  1524.  *
  1525.  * If it's the same as the current request URL, will return false.
  1526.  *
  1527.  * @since 2.0.4
  1528.  *
  1529.  * @return false|string False on failure. Referer URL on success.
  1530.  */
  1531. function wp_get_referer() {
  1532.     if ( ! function_exists( 'wp_validate_redirect' ) ) {
  1533.         return false;
  1534.     }
  1535.  
  1536.     $ref = wp_get_raw_referer();
  1537.  
  1538.     if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) && $ref !== home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) ) {
  1539.         return wp_validate_redirect( $ref, false );
  1540.     }
  1541.  
  1542.     return false;
  1543. }
  1544.  
  1545. /**
  1546.  * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
  1547.  *
  1548.  * Do not use for redirects, use wp_get_referer() instead.
  1549.  *
  1550.  * @since 4.5.0
  1551.  *
  1552.  * @return string|false Referer URL on success, false on failure.
  1553.  */
  1554. function wp_get_raw_referer() {
  1555.     if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
  1556.         return wp_unslash( $_REQUEST['_wp_http_referer'] );
  1557.     } else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
  1558.         return wp_unslash( $_SERVER['HTTP_REFERER'] );
  1559.     }
  1560.  
  1561.     return false;
  1562. }
  1563.  
  1564. /**
  1565.  * Retrieve original referer that was posted, if it exists.
  1566.  *
  1567.  * @since 2.0.4
  1568.  *
  1569.  * @return string|false False if no original referer or original referer if set.
  1570.  */
  1571. function wp_get_original_referer() {
  1572.     if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
  1573.         return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
  1574.     return false;
  1575. }
  1576.  
  1577. /**
  1578.  * Recursive directory creation based on full path.
  1579.  *
  1580.  * Will attempt to set permissions on folders.
  1581.  *
  1582.  * @since 2.0.1
  1583.  *
  1584.  * @param string $target Full path to attempt to create.
  1585.  * @return bool Whether the path was created. True if path already exists.
  1586.  */
  1587. function wp_mkdir_p( $target ) {
  1588.     $wrapper = null;
  1589.  
  1590.     // Strip the protocol.
  1591.     if ( wp_is_stream( $target ) ) {
  1592.         list( $wrapper, $target ) = explode( '://', $target, 2 );
  1593.     }
  1594.  
  1595.     // From php.net/mkdir user contributed notes.
  1596.     $target = str_replace( '//', '/', $target );
  1597.  
  1598.     // Put the wrapper back on the target.
  1599.     if ( $wrapper !== null ) {
  1600.         $target = $wrapper . '://' . $target;
  1601.     }
  1602.  
  1603.     /*
  1604.      * Safe mode fails with a trailing slash under certain PHP versions.
  1605.      * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
  1606.      */
  1607.     $target = rtrim($target, '/');
  1608.     if ( empty($target) )
  1609.         $target = '/';
  1610.  
  1611.     if ( file_exists( $target ) )
  1612.         return @is_dir( $target );
  1613.  
  1614.     // We need to find the permissions of the parent folder that exists and inherit that.
  1615.     $target_parent = dirname( $target );
  1616.     while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
  1617.         $target_parent = dirname( $target_parent );
  1618.     }
  1619.  
  1620.     // Get the permission bits.
  1621.     if ( $stat = @stat( $target_parent ) ) {
  1622.         $dir_perms = $stat['mode'] & 0007777;
  1623.     } else {
  1624.         $dir_perms = 0777;
  1625.     }
  1626.  
  1627.     if ( @mkdir( $target, $dir_perms, true ) ) {
  1628.  
  1629.         /*
  1630.          * If a umask is set that modifies $dir_perms, we'll have to re-set
  1631.          * the $dir_perms correctly with chmod()
  1632.          */
  1633.         if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
  1634.             $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
  1635.             for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
  1636.                 @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
  1637.             }
  1638.         }
  1639.  
  1640.         return true;
  1641.     }
  1642.  
  1643.     return false;
  1644. }
  1645.  
  1646. /**
  1647.  * Test if a give filesystem path is absolute.
  1648.  *
  1649.  * For example, '/foo/bar', or 'c:\windows'.
  1650.  *
  1651.  * @since 2.5.0
  1652.  *
  1653.  * @param string $path File path.
  1654.  * @return bool True if path is absolute, false is not absolute.
  1655.  */
  1656. function path_is_absolute( $path ) {
  1657.     /*
  1658.      * This is definitive if true but fails if $path does not exist or contains
  1659.      * a symbolic link.
  1660.      */
  1661.     if ( realpath($path) == $path )
  1662.         return true;
  1663.  
  1664.     if ( strlen($path) == 0 || $path[0] == '.' )
  1665.         return false;
  1666.  
  1667.     // Windows allows absolute paths like this.
  1668.     if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
  1669.         return true;
  1670.  
  1671.     // A path starting with / or \ is absolute; anything else is relative.
  1672.     return ( $path[0] == '/' || $path[0] == '\\' );
  1673. }
  1674.  
  1675. /**
  1676.  * Join two filesystem paths together.
  1677.  *
  1678.  * For example, 'give me $path relative to $base'. If the $path is absolute,
  1679.  * then it the full path is returned.
  1680.  *
  1681.  * @since 2.5.0
  1682.  *
  1683.  * @param string $base Base path.
  1684.  * @param string $path Path relative to $base.
  1685.  * @return string The path with the base or absolute path.
  1686.  */
  1687. function path_join( $base, $path ) {
  1688.     if ( path_is_absolute($path) )
  1689.         return $path;
  1690.  
  1691.     return rtrim($base, '/') . '/' . ltrim($path, '/');
  1692. }
  1693.  
  1694. /**
  1695.  * Normalize a filesystem path.
  1696.  *
  1697.  * On windows systems, replaces backslashes with forward slashes
  1698.  * and forces upper-case drive letters.
  1699.  * Allows for two leading slashes for Windows network shares, but
  1700.  * ensures that all other duplicate slashes are reduced to a single.
  1701.  *
  1702.  * @since 3.9.0
  1703.  * @since 4.4.0 Ensures upper-case drive letters on Windows systems.
  1704.  * @since 4.5.0 Allows for Windows network shares.
  1705.  *
  1706.  * @param string $path Path to normalize.
  1707.  * @return string Normalized path.
  1708.  */
  1709. function wp_normalize_path( $path ) {
  1710.     $path = str_replace( '\\', '/', $path );
  1711.     $path = preg_replace( '|(?<=.)/+|', '/', $path );
  1712.     if ( ':' === substr( $path, 1, 1 ) ) {
  1713.         $path = ucfirst( $path );
  1714.     }
  1715.     return $path;
  1716. }
  1717.  
  1718. /**
  1719.  * Determine a writable directory for temporary files.
  1720.  *
  1721.  * Function's preference is the return value of sys_get_temp_dir(),
  1722.  * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
  1723.  * before finally defaulting to /tmp/
  1724.  *
  1725.  * In the event that this function does not find a writable location,
  1726.  * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
  1727.  *
  1728.  * @since 2.5.0
  1729.  *
  1730.  * @staticvar string $temp
  1731.  *
  1732.  * @return string Writable temporary directory.
  1733.  */
  1734. function get_temp_dir() {
  1735.     static $temp = '';
  1736.     if ( defined('WP_TEMP_DIR') )
  1737.         return trailingslashit(WP_TEMP_DIR);
  1738.  
  1739.     if ( $temp )
  1740.         return trailingslashit( $temp );
  1741.  
  1742.     if ( function_exists('sys_get_temp_dir') ) {
  1743.         $temp = sys_get_temp_dir();
  1744.         if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
  1745.             return trailingslashit( $temp );
  1746.     }
  1747.  
  1748.     $temp = ini_get('upload_tmp_dir');
  1749.     if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
  1750.         return trailingslashit( $temp );
  1751.  
  1752.     $temp = WP_CONTENT_DIR . '/';
  1753.     if ( is_dir( $temp ) && wp_is_writable( $temp ) )
  1754.         return $temp;
  1755.  
  1756.     return '/tmp/';
  1757. }
  1758.  
  1759. /**
  1760.  * Determine if a directory is writable.
  1761.  *
  1762.  * This function is used to work around certain ACL issues in PHP primarily
  1763.  * affecting Windows Servers.
  1764.  *
  1765.  * @since 3.6.0
  1766.  *
  1767.  * @see win_is_writable()
  1768.  *
  1769.  * @param string $path Path to check for write-ability.
  1770.  * @return bool Whether the path is writable.
  1771.  */
  1772. function wp_is_writable( $path ) {
  1773.     if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
  1774.         return win_is_writable( $path );
  1775.     else
  1776.         return @is_writable( $path );
  1777. }
  1778.  
  1779. /**
  1780.  * Workaround for Windows bug in is_writable() function
  1781.  *
  1782.  * PHP has issues with Windows ACL's for determine if a
  1783.  * directory is writable or not, this works around them by
  1784.  * checking the ability to open files rather than relying
  1785.  * upon PHP to interprate the OS ACL.
  1786.  *
  1787.  * @since 2.8.0
  1788.  *
  1789.  * @see https://bugs.php.net/bug.php?id=27609
  1790.  * @see https://bugs.php.net/bug.php?id=30931
  1791.  *
  1792.  * @param string $path Windows path to check for write-ability.
  1793.  * @return bool Whether the path is writable.
  1794.  */
  1795. function win_is_writable( $path ) {
  1796.  
  1797.     if ( $path[strlen( $path ) - 1] == '/' ) { // if it looks like a directory, check a random file within the directory
  1798.         return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
  1799.     } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
  1800.         return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
  1801.     }
  1802.     // check tmp file for read/write capabilities
  1803.     $should_delete_tmp_file = !file_exists( $path );
  1804.     $f = @fopen( $path, 'a' );
  1805.     if ( $f === false )
  1806.         return false;
  1807.     fclose( $f );
  1808.     if ( $should_delete_tmp_file )
  1809.         unlink( $path );
  1810.     return true;
  1811. }
  1812.  
  1813. /**
  1814.  * Retrieves uploads directory information.
  1815.  *
  1816.  * Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
  1817.  * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
  1818.  * when not uploading files.
  1819.  *
  1820.  * @since 4.5.0
  1821.  *
  1822.  * @see wp_upload_dir()
  1823.  *
  1824.  * @return array See wp_upload_dir() for description.
  1825.  */
  1826. function wp_get_upload_dir() {
  1827.     return wp_upload_dir( null, false );
  1828. }
  1829.  
  1830. /**
  1831.  * Get an array containing the current upload directory's path and url.
  1832.  *
  1833.  * Checks the 'upload_path' option, which should be from the web root folder,
  1834.  * and if it isn't empty it will be used. If it is empty, then the path will be
  1835.  * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
  1836.  * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
  1837.  *
  1838.  * The upload URL path is set either by the 'upload_url_path' option or by using
  1839.  * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
  1840.  *
  1841.  * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
  1842.  * the administration settings panel), then the time will be used. The format
  1843.  * will be year first and then month.
  1844.  *
  1845.  * If the path couldn't be created, then an error will be returned with the key
  1846.  * 'error' containing the error message. The error suggests that the parent
  1847.  * directory is not writable by the server.
  1848.  *
  1849.  * On success, the returned array will have many indices:
  1850.  * 'path' - base directory and sub directory or full path to upload directory.
  1851.  * 'url' - base url and sub directory or absolute URL to upload directory.
  1852.  * 'subdir' - sub directory if uploads use year/month folders option is on.
  1853.  * 'basedir' - path without subdir.
  1854.  * 'baseurl' - URL path without subdir.
  1855.  * 'error' - false or error message.
  1856.  *
  1857.  * @since 2.0.0
  1858.  * @uses _wp_upload_dir()
  1859.  *
  1860.  * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
  1861.  * @param bool   $create_dir Optional. Whether to check and create the uploads directory.
  1862.  *                           Default true for backward compatibility.
  1863.  * @param bool   $refresh_cache Optional. Whether to refresh the cache. Default false.
  1864.  * @return array See above for description.
  1865.  */
  1866. function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
  1867.     static $cache = array(), $tested_paths = array();
  1868.  
  1869.     $key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );
  1870.  
  1871.     if ( $refresh_cache || empty( $cache[ $key ] ) ) {
  1872.         $cache[ $key ] = _wp_upload_dir( $time );
  1873.     }
  1874.  
  1875.     /**
  1876.      * Filters the uploads directory data.
  1877.      *
  1878.      * @since 2.0.0
Advertisement
Add Comment
Please, Sign In to add comment