Advertisement
Guest User

Hyperz - WP 3.2.1 XSS Fix

a guest
Sep 7th, 2011
1,622
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 42.65 KB | None | 0 0
  1. <?php
  2. /**
  3.  * WordPress Post Template Functions.
  4.  *
  5.  * Gets content for the current post in the loop.
  6.  *
  7.  * @package WordPress
  8.  * @subpackage Template
  9.  */
  10.  
  11. /**
  12.  * Display the ID of the current item in the WordPress Loop.
  13.  *
  14.  * @since 0.71
  15.  */
  16. function the_ID() {
  17.     echo get_the_ID();
  18. }
  19.  
  20. /**
  21.  * Retrieve the ID of the current item in the WordPress Loop.
  22.  *
  23.  * @since 2.1.0
  24.  * @uses $post
  25.  *
  26.  * @return int
  27.  */
  28. function get_the_ID() {
  29.     global $post;
  30.     return $post->ID;
  31. }
  32.  
  33. /**
  34.  * Display or retrieve the current post title with optional content.
  35.  *
  36.  * @since 0.71
  37.  *
  38.  * @param string $before Optional. Content to prepend to the title.
  39.  * @param string $after Optional. Content to append to the title.
  40.  * @param bool $echo Optional, default to true.Whether to display or return.
  41.  * @return null|string Null on no title. String if $echo parameter is false.
  42.  */
  43. function the_title($before = '', $after = '', $echo = true) {
  44.     $title = get_the_title();
  45.  
  46.     if ( strlen($title) == 0 )
  47.         return;
  48.  
  49.     $title = $before . $title . $after;
  50.  
  51.     if ( $echo )
  52.         echo htmlentities($title);
  53.     else
  54.         return htmlentities($title);
  55. }
  56.  
  57. /**
  58.  * Sanitize the current title when retrieving or displaying.
  59.  *
  60.  * Works like {@link the_title()}, except the parameters can be in a string or
  61.  * an array. See the function for what can be override in the $args parameter.
  62.  *
  63.  * The title before it is displayed will have the tags stripped and {@link
  64.  * esc_attr()} before it is passed to the user or displayed. The default
  65.  * as with {@link the_title()}, is to display the title.
  66.  *
  67.  * @since 2.3.0
  68.  *
  69.  * @param string|array $args Optional. Override the defaults.
  70.  * @return string|null Null on failure or display. String when echo is false.
  71.  */
  72. function the_title_attribute( $args = '' ) {
  73.     $title = get_the_title();
  74.  
  75.     if ( strlen($title) == 0 )
  76.         return;
  77.  
  78.     $defaults = array('before' => '', 'after' =>  '', 'echo' => true);
  79.     $r = wp_parse_args($args, $defaults);
  80.     extract( $r, EXTR_SKIP );
  81.  
  82.  
  83.     $title = $before . $title . $after;
  84.     $title = esc_attr(strip_tags($title));
  85.  
  86.     if ( $echo )
  87.         echo htmlentities($title);
  88.     else
  89.         return htmlentities($title);
  90. }
  91.  
  92. /**
  93.  * Retrieve post title.
  94.  *
  95.  * If the post is protected and the visitor is not an admin, then "Protected"
  96.  * will be displayed before the post title. If the post is private, then
  97.  * "Private" will be located before the post title.
  98.  *
  99.  * @since 0.71
  100.  *
  101.  * @param int $id Optional. Post ID.
  102.  * @return string
  103.  */
  104. function get_the_title( $id = 0 ) {
  105.     $post = &get_post($id);
  106.  
  107.     $title = isset($post->post_title) ? $post->post_title : '';
  108.     $id = isset($post->ID) ? $post->ID : (int) $id;
  109.  
  110.     if ( !is_admin() ) {
  111.         if ( !empty($post->post_password) ) {
  112.             $protected_title_format = apply_filters('protected_title_format', __('Protected: %s'));
  113.             $title = sprintf($protected_title_format, $title);
  114.         } else if ( isset($post->post_status) && 'private' == $post->post_status ) {
  115.             $private_title_format = apply_filters('private_title_format', __('Private: %s'));
  116.             $title = sprintf($private_title_format, $title);
  117.         }
  118.     }
  119.     return htmlentities(apply_filters( 'the_title', $title, $id ));
  120. }
  121.  
  122. /**
  123.  * Display the Post Global Unique Identifier (guid).
  124.  *
  125.  * The guid will appear to be a link, but should not be used as an link to the
  126.  * post. The reason you should not use it as a link, is because of moving the
  127.  * blog across domains.
  128.  *
  129.  * Url is escaped to make it xml safe
  130.  *
  131.  * @since 1.5.0
  132.  *
  133.  * @param int $id Optional. Post ID.
  134.  */
  135. function the_guid( $id = 0 ) {
  136.     echo esc_url( get_the_guid( $id ) );
  137. }
  138.  
  139. /**
  140.  * Retrieve the Post Global Unique Identifier (guid).
  141.  *
  142.  * The guid will appear to be a link, but should not be used as an link to the
  143.  * post. The reason you should not use it as a link, is because of moving the
  144.  * blog across domains.
  145.  *
  146.  * @since 1.5.0
  147.  *
  148.  * @param int $id Optional. Post ID.
  149.  * @return string
  150.  */
  151. function get_the_guid( $id = 0 ) {
  152.     $post = &get_post($id);
  153.  
  154.     return apply_filters('get_the_guid', $post->guid);
  155. }
  156.  
  157. /**
  158.  * Display the post content.
  159.  *
  160.  * @since 0.71
  161.  *
  162.  * @param string $more_link_text Optional. Content for when there is more text.
  163.  * @param string $stripteaser Optional. Teaser content before the more text.
  164.  */
  165. function the_content($more_link_text = null, $stripteaser = 0) {
  166.     $content = get_the_content($more_link_text, $stripteaser);
  167.     $content = apply_filters('the_content', $content);
  168.     $content = str_replace(']]>', ']]&gt;', $content);
  169.     echo $content;
  170. }
  171.  
  172. /**
  173.  * Retrieve the post content.
  174.  *
  175.  * @since 0.71
  176.  *
  177.  * @param string $more_link_text Optional. Content for when there is more text.
  178.  * @param string $stripteaser Optional. Teaser content before the more text.
  179.  * @return string
  180.  */
  181. function get_the_content($more_link_text = null, $stripteaser = 0) {
  182.     global $post, $more, $page, $pages, $multipage, $preview;
  183.  
  184.     if ( null === $more_link_text )
  185.         $more_link_text = __( '(more...)' );
  186.  
  187.     $output = '';
  188.     $hasTeaser = false;
  189.  
  190.     // If post password required and it doesn't match the cookie.
  191.     if ( post_password_required($post) ) {
  192.         $output = get_the_password_form();
  193.         return $output;
  194.     }
  195.  
  196.     if ( $page > count($pages) ) // if the requested page doesn't exist
  197.         $page = count($pages); // give them the highest numbered page that DOES exist
  198.  
  199.     $content = $pages[$page-1];
  200.     if ( preg_match('/<!--more(.*?)?-->/', $content, $matches) ) {
  201.         $content = explode($matches[0], $content, 2);
  202.         if ( !empty($matches[1]) && !empty($more_link_text) )
  203.             $more_link_text = strip_tags(wp_kses_no_null(trim($matches[1])));
  204.  
  205.         $hasTeaser = true;
  206.     } else {
  207.         $content = array($content);
  208.     }
  209.     if ( (false !== strpos($post->post_content, '<!--noteaser-->') && ((!$multipage) || ($page==1))) )
  210.         $stripteaser = 1;
  211.     $teaser = $content[0];
  212.     if ( ($more) && ($stripteaser) && ($hasTeaser) )
  213.         $teaser = '';
  214.     $output .= $teaser;
  215.     if ( count($content) > 1 ) {
  216.         if ( $more ) {
  217.             $output .= '<span id="more-' . $post->ID . '"></span>' . $content[1];
  218.         } else {
  219.             if ( ! empty($more_link_text) )
  220.                 $output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
  221.             $output = force_balance_tags($output);
  222.         }
  223.  
  224.     }
  225.     if ( $preview ) // preview fix for javascript bug with foreign languages
  226.         $output =   preg_replace_callback('/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output);
  227.  
  228.     return $output;
  229. }
  230.  
  231. /**
  232.  * Preview fix for javascript bug with foreign languages
  233.  *
  234.  * @since 3.1.0
  235.  * @access private
  236.  * @param array $match Match array from preg_replace_callback
  237.  * @returns string
  238.  */
  239. function _convert_urlencoded_to_entities( $match ) {
  240.     return '&#' . base_convert( $match[1], 16, 10 ) . ';';
  241. }
  242.  
  243. /**
  244.  * Display the post excerpt.
  245.  *
  246.  * @since 0.71
  247.  * @uses apply_filters() Calls 'the_excerpt' hook on post excerpt.
  248.  */
  249. function the_excerpt() {
  250.     echo apply_filters('the_excerpt', get_the_excerpt());
  251. }
  252.  
  253. /**
  254.  * Retrieve the post excerpt.
  255.  *
  256.  * @since 0.71
  257.  *
  258.  * @param mixed $deprecated Not used.
  259.  * @return string
  260.  */
  261. function get_the_excerpt( $deprecated = '' ) {
  262.     if ( !empty( $deprecated ) )
  263.         _deprecated_argument( __FUNCTION__, '2.3' );
  264.  
  265.     global $post;
  266.     $output = $post->post_excerpt;
  267.     if ( post_password_required($post) ) {
  268.         $output = __('There is no excerpt because this is a protected post.');
  269.         return $output;
  270.     }
  271.  
  272.     return apply_filters('get_the_excerpt', $output);
  273. }
  274.  
  275. /**
  276.  * Whether post has excerpt.
  277.  *
  278.  * @since 2.3.0
  279.  *
  280.  * @param int $id Optional. Post ID.
  281.  * @return bool
  282.  */
  283. function has_excerpt( $id = 0 ) {
  284.     $post = &get_post( $id );
  285.     return ( !empty( $post->post_excerpt ) );
  286. }
  287.  
  288. /**
  289.  * Display the classes for the post div.
  290.  *
  291.  * @since 2.7.0
  292.  *
  293.  * @param string|array $class One or more classes to add to the class list.
  294.  * @param int $post_id An optional post ID.
  295.  */
  296. function post_class( $class = '', $post_id = null ) {
  297.     // Separates classes with a single space, collates classes for post DIV
  298.     echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"';
  299. }
  300.  
  301. /**
  302.  * Retrieve the classes for the post div as an array.
  303.  *
  304.  * The class names are add are many. If the post is a sticky, then the 'sticky'
  305.  * class name. The class 'hentry' is always added to each post. For each
  306.  * category, the class will be added with 'category-' with category slug is
  307.  * added. The tags are the same way as the categories with 'tag-' before the tag
  308.  * slug. All classes are passed through the filter, 'post_class' with the list
  309.  * of classes, followed by $class parameter value, with the post ID as the last
  310.  * parameter.
  311.  *
  312.  * @since 2.7.0
  313.  *
  314.  * @param string|array $class One or more classes to add to the class list.
  315.  * @param int $post_id An optional post ID.
  316.  * @return array Array of classes.
  317.  */
  318. function get_post_class( $class = '', $post_id = null ) {
  319.     $post = get_post($post_id);
  320.  
  321.     $classes = array();
  322.  
  323.     if ( empty($post) )
  324.         return $classes;
  325.  
  326.     $classes[] = 'post-' . $post->ID;
  327.     $classes[] = $post->post_type;
  328.     $classes[] = 'type-' . $post->post_type;
  329.     $classes[] = 'status-' . $post->post_status;
  330.  
  331.     // Post Format
  332.     $post_format = get_post_format( $post->ID );
  333.  
  334.     if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
  335.         if ( $post_format && !is_wp_error($post_format) )
  336.             $classes[] = 'format-' . sanitize_html_class( $post_format );
  337.         else
  338.             $classes[] = 'format-standard';
  339.     }
  340.  
  341.     // post requires password
  342.     if ( post_password_required($post->ID) )
  343.         $classes[] = 'post-password-required';
  344.  
  345.     // sticky for Sticky Posts
  346.     if ( is_sticky($post->ID) && is_home() && !is_paged() )
  347.         $classes[] = 'sticky';
  348.  
  349.     // hentry for hAtom compliance
  350.     $classes[] = 'hentry';
  351.  
  352.     // Categories
  353.     if ( is_object_in_taxonomy( $post->post_type, 'category' ) ) {
  354.         foreach ( (array) get_the_category($post->ID) as $cat ) {
  355.             if ( empty($cat->slug ) )
  356.                 continue;
  357.             $classes[] = 'category-' . sanitize_html_class($cat->slug, $cat->term_id);
  358.         }
  359.     }
  360.  
  361.     // Tags
  362.     if ( is_object_in_taxonomy( $post->post_type, 'post_tag' ) ) {
  363.         foreach ( (array) get_the_tags($post->ID) as $tag ) {
  364.             if ( empty($tag->slug ) )
  365.                 continue;
  366.             $classes[] = 'tag-' . sanitize_html_class($tag->slug, $tag->term_id);
  367.         }
  368.     }
  369.  
  370.     if ( !empty($class) ) {
  371.         if ( !is_array( $class ) )
  372.             $class = preg_split('#\s+#', $class);
  373.         $classes = array_merge($classes, $class);
  374.     }
  375.  
  376.     $classes = array_map('esc_attr', $classes);
  377.  
  378.     return apply_filters('post_class', $classes, $class, $post->ID);
  379. }
  380.  
  381. /**
  382.  * Display the classes for the body element.
  383.  *
  384.  * @since 2.8.0
  385.  *
  386.  * @param string|array $class One or more classes to add to the class list.
  387.  */
  388. function body_class( $class = '' ) {
  389.     // Separates classes with a single space, collates classes for body element
  390.     echo 'class="' . join( ' ', get_body_class( $class ) ) . '"';
  391. }
  392.  
  393. /**
  394.  * Retrieve the classes for the body element as an array.
  395.  *
  396.  * @since 2.8.0
  397.  *
  398.  * @param string|array $class One or more classes to add to the class list.
  399.  * @return array Array of classes.
  400.  */
  401. function get_body_class( $class = '' ) {
  402.     global $wp_query, $wpdb;
  403.  
  404.     $classes = array();
  405.  
  406.     if ( is_rtl() )
  407.         $classes[] = 'rtl';
  408.  
  409.     if ( is_front_page() )
  410.         $classes[] = 'home';
  411.     if ( is_home() )
  412.         $classes[] = 'blog';
  413.     if ( is_archive() )
  414.         $classes[] = 'archive';
  415.     if ( is_date() )
  416.         $classes[] = 'date';
  417.     if ( is_search() )
  418.         $classes[] = 'search';
  419.     if ( is_paged() )
  420.         $classes[] = 'paged';
  421.     if ( is_attachment() )
  422.         $classes[] = 'attachment';
  423.     if ( is_404() )
  424.         $classes[] = 'error404';
  425.  
  426.     if ( is_single() ) {
  427.         $post_id = $wp_query->get_queried_object_id();
  428.         $post = $wp_query->get_queried_object();
  429.  
  430.         $classes[] = 'single';
  431.         $classes[] = 'single-' . sanitize_html_class($post->post_type, $post_id);
  432.         $classes[] = 'postid-' . $post_id;
  433.  
  434.         // Post Format
  435.         $post_format = get_post_format( $post->ID );
  436.  
  437.         if ( $post_format && !is_wp_error($post_format) )
  438.             $classes[] = 'single-format-' . sanitize_html_class( $post_format );
  439.         else
  440.             $classes[] = 'single-format-standard';
  441.  
  442.         if ( is_attachment() ) {
  443.             $mime_type = get_post_mime_type($post_id);
  444.             $mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' );
  445.             $classes[] = 'attachmentid-' . $post_id;
  446.             $classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type );
  447.         }
  448.     } elseif ( is_archive() ) {
  449.         if ( is_post_type_archive() ) {
  450.             $classes[] = 'post-type-archive';
  451.             $classes[] = 'post-type-archive-' . sanitize_html_class( get_query_var( 'post_type' ) );
  452.         } else if ( is_author() ) {
  453.             $author = $wp_query->get_queried_object();
  454.             $classes[] = 'author';
  455.             $classes[] = 'author-' . sanitize_html_class( $author->user_nicename , $author->ID );
  456.             $classes[] = 'author-' . $author->ID;
  457.         } elseif ( is_category() ) {
  458.             $cat = $wp_query->get_queried_object();
  459.             $classes[] = 'category';
  460.             $classes[] = 'category-' . sanitize_html_class( $cat->slug, $cat->term_id );
  461.             $classes[] = 'category-' . $cat->term_id;
  462.         } elseif ( is_tag() ) {
  463.             $tags = $wp_query->get_queried_object();
  464.             $classes[] = 'tag';
  465.             $classes[] = 'tag-' . sanitize_html_class( $tags->slug, $tags->term_id );
  466.             $classes[] = 'tag-' . $tags->term_id;
  467.         } elseif ( is_tax() ) {
  468.             $term = $wp_query->get_queried_object();
  469.             $classes[] = 'tax-' . sanitize_html_class( $term->taxonomy );
  470.             $classes[] = 'term-' . sanitize_html_class( $term->slug, $term->term_id );
  471.             $classes[] = 'term-' . $term->term_id;
  472.         }
  473.     } elseif ( is_page() ) {
  474.         $classes[] = 'page';
  475.  
  476.         $page_id = $wp_query->get_queried_object_id();
  477.  
  478.         $post = get_page($page_id);
  479.  
  480.         $classes[] = 'page-id-' . $page_id;
  481.  
  482.         if ( $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' AND post_status = 'publish' LIMIT 1", $page_id) ) )
  483.             $classes[] = 'page-parent';
  484.  
  485.         if ( $post->post_parent ) {
  486.             $classes[] = 'page-child';
  487.             $classes[] = 'parent-pageid-' . $post->post_parent;
  488.         }
  489.         if ( is_page_template() ) {
  490.             $classes[] = 'page-template';
  491.             $classes[] = 'page-template-' . sanitize_html_class( str_replace( '.', '-', get_post_meta( $page_id, '_wp_page_template', true ) ), '' );
  492.         } else {
  493.             $classes[] = 'page-template-default';
  494.         }
  495.     } elseif ( is_search() ) {
  496.         if ( !empty( $wp_query->posts ) )
  497.             $classes[] = 'search-results';
  498.         else
  499.             $classes[] = 'search-no-results';
  500.     }
  501.  
  502.     if ( is_user_logged_in() )
  503.         $classes[] = 'logged-in';
  504.  
  505.     if ( is_admin_bar_showing() )
  506.         $classes[] = 'admin-bar';
  507.  
  508.     $page = $wp_query->get( 'page' );
  509.  
  510.     if ( !$page || $page < 2)
  511.         $page = $wp_query->get( 'paged' );
  512.  
  513.     if ( $page && $page > 1 ) {
  514.         $classes[] = 'paged-' . $page;
  515.  
  516.         if ( is_single() )
  517.             $classes[] = 'single-paged-' . $page;
  518.         elseif ( is_page() )
  519.             $classes[] = 'page-paged-' . $page;
  520.         elseif ( is_category() )
  521.             $classes[] = 'category-paged-' . $page;
  522.         elseif ( is_tag() )
  523.             $classes[] = 'tag-paged-' . $page;
  524.         elseif ( is_date() )
  525.             $classes[] = 'date-paged-' . $page;
  526.         elseif ( is_author() )
  527.             $classes[] = 'author-paged-' . $page;
  528.         elseif ( is_search() )
  529.             $classes[] = 'search-paged-' . $page;
  530.         elseif ( is_post_type_archive() )
  531.             $classes[] = 'post-type-paged-' . $page;
  532.     }
  533.  
  534.     if ( ! empty( $class ) ) {
  535.         if ( !is_array( $class ) )
  536.             $class = preg_split( '#\s+#', $class );
  537.         $classes = array_merge( $classes, $class );
  538.     } else {
  539.         // Ensure that we always coerce class to being an array.
  540.         $class = array();
  541.     }
  542.  
  543.     $classes = array_map( 'esc_attr', $classes );
  544.  
  545.     return apply_filters( 'body_class', $classes, $class );
  546. }
  547.  
  548. /**
  549.  * Whether post requires password and correct password has been provided.
  550.  *
  551.  * @since 2.7.0
  552.  *
  553.  * @param int|object $post An optional post.  Global $post used if not provided.
  554.  * @return bool false if a password is not required or the correct password cookie is present, true otherwise.
  555.  */
  556. function post_password_required( $post = null ) {
  557.     $post = get_post($post);
  558.  
  559.     if ( empty($post->post_password) )
  560.         return false;
  561.  
  562.     if ( !isset($_COOKIE['wp-postpass_' . COOKIEHASH]) )
  563.         return true;
  564.  
  565.     if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password )
  566.         return true;
  567.  
  568.     return false;
  569. }
  570.  
  571. /**
  572.  * Display "sticky" CSS class, if a post is sticky.
  573.  *
  574.  * @since 2.7.0
  575.  *
  576.  * @param int $post_id An optional post ID.
  577.  */
  578. function sticky_class( $post_id = null ) {
  579.     if ( !is_sticky($post_id) )
  580.         return;
  581.  
  582.     echo " sticky";
  583. }
  584.  
  585. /**
  586.  * Page Template Functions for usage in Themes
  587.  *
  588.  * @package WordPress
  589.  * @subpackage Template
  590.  */
  591.  
  592. /**
  593.  * The formatted output of a list of pages.
  594.  *
  595.  * Displays page links for paginated posts (i.e. includes the <!--nextpage-->.
  596.  * Quicktag one or more times). This tag must be within The Loop.
  597.  *
  598.  * The defaults for overwriting are:
  599.  * 'next_or_number' - Default is 'number' (string). Indicates whether page
  600.  *      numbers should be used. Valid values are number and next.
  601.  * 'nextpagelink' - Default is 'Next Page' (string). Text for link to next page.
  602.  *      of the bookmark.
  603.  * 'previouspagelink' - Default is 'Previous Page' (string). Text for link to
  604.  *      previous page, if available.
  605.  * 'pagelink' - Default is '%' (String).Format string for page numbers. The % in
  606.  *      the parameter string will be replaced with the page number, so Page %
  607.  *      generates "Page 1", "Page 2", etc. Defaults to %, just the page number.
  608.  * 'before' - Default is '<p> Pages:' (string). The html or text to prepend to
  609.  *      each bookmarks.
  610.  * 'after' - Default is '</p>' (string). The html or text to append to each
  611.  *      bookmarks.
  612.  * 'link_before' - Default is '' (string). The html or text to prepend to each
  613.  *      Pages link inside the <a> tag. Also prepended to the current item, which
  614.  *      is not linked.
  615.  * 'link_after' - Default is '' (string). The html or text to append to each
  616.  *      Pages link inside the <a> tag. Also appended to the current item, which
  617.  *      is not linked.
  618.  *
  619.  * @since 1.2.0
  620.  * @access private
  621.  *
  622.  * @param string|array $args Optional. Overwrite the defaults.
  623.  * @return string Formatted output in HTML.
  624.  */
  625. function wp_link_pages($args = '') {
  626.     $defaults = array(
  627.         'before' => '<p>' . __('Pages:'), 'after' => '</p>',
  628.         'link_before' => '', 'link_after' => '',
  629.         'next_or_number' => 'number', 'nextpagelink' => __('Next page'),
  630.         'previouspagelink' => __('Previous page'), 'pagelink' => '%',
  631.         'echo' => 1
  632.     );
  633.  
  634.     $r = wp_parse_args( $args, $defaults );
  635.     $r = apply_filters( 'wp_link_pages_args', $r );
  636.     extract( $r, EXTR_SKIP );
  637.  
  638.     global $page, $numpages, $multipage, $more, $pagenow;
  639.  
  640.     $output = '';
  641.     if ( $multipage ) {
  642.         if ( 'number' == $next_or_number ) {
  643.             $output .= $before;
  644.             for ( $i = 1; $i < ($numpages+1); $i = $i + 1 ) {
  645.                 $j = str_replace('%',$i,$pagelink);
  646.                 $output .= ' ';
  647.                 if ( ($i != $page) || ((!$more) && ($page==1)) ) {
  648.                     $output .= _wp_link_page($i);
  649.                 }
  650.                 $output .= $link_before . $j . $link_after;
  651.                 if ( ($i != $page) || ((!$more) && ($page==1)) )
  652.                     $output .= '</a>';
  653.             }
  654.             $output .= $after;
  655.         } else {
  656.             if ( $more ) {
  657.                 $output .= $before;
  658.                 $i = $page - 1;
  659.                 if ( $i && $more ) {
  660.                     $output .= _wp_link_page($i);
  661.                     $output .= $link_before. $previouspagelink . $link_after . '</a>';
  662.                 }
  663.                 $i = $page + 1;
  664.                 if ( $i <= $numpages && $more ) {
  665.                     $output .= _wp_link_page($i);
  666.                     $output .= $link_before. $nextpagelink . $link_after . '</a>';
  667.                 }
  668.                 $output .= $after;
  669.             }
  670.         }
  671.     }
  672.  
  673.     if ( $echo )
  674.         echo $output;
  675.  
  676.     return $output;
  677. }
  678.  
  679. /**
  680.  * Helper function for wp_link_pages().
  681.  *
  682.  * @since 3.1.0
  683.  * @access private
  684.  *
  685.  * @param int $i Page number.
  686.  * @return string Link.
  687.  */
  688. function _wp_link_page( $i ) {
  689.     global $post, $wp_rewrite;
  690.  
  691.     if ( 1 == $i ) {
  692.         $url = get_permalink();
  693.     } else {
  694.         if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
  695.             $url = add_query_arg( 'page', $i, get_permalink() );
  696.         elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') == $post->ID )
  697.             $url = trailingslashit(get_permalink()) . user_trailingslashit("$wp_rewrite->pagination_base/" . $i, 'single_paged');
  698.         else
  699.             $url = trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged');
  700.     }
  701.  
  702.     return '<a href="' . esc_url( $url ) . '">';
  703. }
  704.  
  705. //
  706. // Post-meta: Custom per-post fields.
  707. //
  708.  
  709. /**
  710.  * Retrieve post custom meta data field.
  711.  *
  712.  * @since 1.5.0
  713.  *
  714.  * @param string $key Meta data key name.
  715.  * @return bool|string|array Array of values or single value, if only one element exists. False will be returned if key does not exist.
  716.  */
  717. function post_custom( $key = '' ) {
  718.     $custom = get_post_custom();
  719.  
  720.     if ( !isset( $custom[$key] ) )
  721.         return false;
  722.     elseif ( 1 == count($custom[$key]) )
  723.         return $custom[$key][0];
  724.     else
  725.         return $custom[$key];
  726. }
  727.  
  728. /**
  729.  * Display list of post custom fields.
  730.  *
  731.  * @internal This will probably change at some point...
  732.  * @since 1.2.0
  733.  * @uses apply_filters() Calls 'the_meta_key' on list item HTML content, with key and value as separate parameters.
  734.  */
  735. function the_meta() {
  736.     if ( $keys = get_post_custom_keys() ) {
  737.         echo "<ul class='post-meta'>\n";
  738.         foreach ( (array) $keys as $key ) {
  739.             $keyt = trim($key);
  740.             if ( '_' == $keyt[0] )
  741.                 continue;
  742.             $values = array_map('trim', get_post_custom_values($key));
  743.             $value = implode($values,', ');
  744.             echo apply_filters('the_meta_key', "<li><span class='post-meta-key'>$key:</span> $value</li>\n", $key, $value);
  745.         }
  746.         echo "</ul>\n";
  747.     }
  748. }
  749.  
  750. //
  751. // Pages
  752. //
  753.  
  754. /**
  755.  * Retrieve or display list of pages as a dropdown (select list).
  756.  *
  757.  * @since 2.1.0
  758.  *
  759.  * @param array|string $args Optional. Override default arguments.
  760.  * @return string HTML content, if not displaying.
  761.  */
  762. function wp_dropdown_pages($args = '') {
  763.     $defaults = array(
  764.         'depth' => 0, 'child_of' => 0,
  765.         'selected' => 0, 'echo' => 1,
  766.         'name' => 'page_id', 'id' => '',
  767.         'show_option_none' => '', 'show_option_no_change' => '',
  768.         'option_none_value' => ''
  769.     );
  770.  
  771.     $r = wp_parse_args( $args, $defaults );
  772.     extract( $r, EXTR_SKIP );
  773.  
  774.     $pages = get_pages($r);
  775.     $output = '';
  776.     $name = esc_attr($name);
  777.     // Back-compat with old system where both id and name were based on $name argument
  778.     if ( empty($id) )
  779.         $id = $name;
  780.  
  781.     if ( ! empty($pages) ) {
  782.         $output = "<select name=\"$name\" id=\"$id\">\n";
  783.         if ( $show_option_no_change )
  784.             $output .= "\t<option value=\"-1\">$show_option_no_change</option>";
  785.         if ( $show_option_none )
  786.             $output .= "\t<option value=\"" . esc_attr($option_none_value) . "\">$show_option_none</option>\n";
  787.         $output .= walk_page_dropdown_tree($pages, $depth, $r);
  788.         $output .= "</select>\n";
  789.     }
  790.  
  791.     $output = apply_filters('wp_dropdown_pages', $output);
  792.  
  793.     if ( $echo )
  794.         echo $output;
  795.  
  796.     return $output;
  797. }
  798.  
  799. /**
  800.  * Retrieve or display list of pages in list (li) format.
  801.  *
  802.  * @since 1.5.0
  803.  *
  804.  * @param array|string $args Optional. Override default arguments.
  805.  * @return string HTML content, if not displaying.
  806.  */
  807. function wp_list_pages($args = '') {
  808.     $defaults = array(
  809.         'depth' => 0, 'show_date' => '',
  810.         'date_format' => get_option('date_format'),
  811.         'child_of' => 0, 'exclude' => '',
  812.         'title_li' => __('Pages'), 'echo' => 1,
  813.         'authors' => '', 'sort_column' => 'menu_order, post_title',
  814.         'link_before' => '', 'link_after' => '', 'walker' => '',
  815.     );
  816.  
  817.     $r = wp_parse_args( $args, $defaults );
  818.     extract( $r, EXTR_SKIP );
  819.  
  820.     $output = '';
  821.     $current_page = 0;
  822.  
  823.     // sanitize, mostly to keep spaces out
  824.     $r['exclude'] = preg_replace('/[^0-9,]/', '', $r['exclude']);
  825.  
  826.     // Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array)
  827.     $exclude_array = ( $r['exclude'] ) ? explode(',', $r['exclude']) : array();
  828.     $r['exclude'] = implode( ',', apply_filters('wp_list_pages_excludes', $exclude_array) );
  829.  
  830.     // Query pages.
  831.     $r['hierarchical'] = 0;
  832.     $pages = get_pages($r);
  833.  
  834.     if ( !empty($pages) ) {
  835.         if ( $r['title_li'] )
  836.             $output .= '<li class="pagenav">' . $r['title_li'] . '<ul>';
  837.  
  838.         global $wp_query;
  839.         if ( is_page() || is_attachment() || $wp_query->is_posts_page )
  840.             $current_page = $wp_query->get_queried_object_id();
  841.         $output .= walk_page_tree($pages, $r['depth'], $current_page, $r);
  842.  
  843.         if ( $r['title_li'] )
  844.             $output .= '</ul></li>';
  845.     }
  846.  
  847.     $output = apply_filters('wp_list_pages', $output, $r);
  848.  
  849.     if ( $r['echo'] )
  850.         echo $output;
  851.     else
  852.         return $output;
  853. }
  854.  
  855. /**
  856.  * Display or retrieve list of pages with optional home link.
  857.  *
  858.  * The arguments are listed below and part of the arguments are for {@link
  859.  * wp_list_pages()} function. Check that function for more info on those
  860.  * arguments.
  861.  *
  862.  * <ul>
  863.  * <li><strong>sort_column</strong> - How to sort the list of pages. Defaults
  864.  * to page title. Use column for posts table.</li>
  865.  * <li><strong>menu_class</strong> - Class to use for the div ID which contains
  866.  * the page list. Defaults to 'menu'.</li>
  867.  * <li><strong>echo</strong> - Whether to echo list or return it. Defaults to
  868.  * echo.</li>
  869.  * <li><strong>link_before</strong> - Text before show_home argument text.</li>
  870.  * <li><strong>link_after</strong> - Text after show_home argument text.</li>
  871.  * <li><strong>show_home</strong> - If you set this argument, then it will
  872.  * display the link to the home page. The show_home argument really just needs
  873.  * to be set to the value of the text of the link.</li>
  874.  * </ul>
  875.  *
  876.  * @since 2.7.0
  877.  *
  878.  * @param array|string $args
  879.  */
  880. function wp_page_menu( $args = array() ) {
  881.     $defaults = array('sort_column' => 'menu_order, post_title', 'menu_class' => 'menu', 'echo' => true, 'link_before' => '', 'link_after' => '');
  882.     $args = wp_parse_args( $args, $defaults );
  883.     $args = apply_filters( 'wp_page_menu_args', $args );
  884.  
  885.     $menu = '';
  886.  
  887.     $list_args = $args;
  888.  
  889.     // Show Home in the menu
  890.     if ( ! empty($args['show_home']) ) {
  891.         if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] )
  892.             $text = __('Home');
  893.         else
  894.             $text = $args['show_home'];
  895.         $class = '';
  896.         if ( is_front_page() && !is_paged() )
  897.             $class = 'class="current_page_item"';
  898.         $menu .= '<li ' . $class . '><a href="' . home_url( '/' ) . '" title="' . esc_attr($text) . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>';
  899.         // If the front page is a page, add it to the exclude list
  900.         if (get_option('show_on_front') == 'page') {
  901.             if ( !empty( $list_args['exclude'] ) ) {
  902.                 $list_args['exclude'] .= ',';
  903.             } else {
  904.                 $list_args['exclude'] = '';
  905.             }
  906.             $list_args['exclude'] .= get_option('page_on_front');
  907.         }
  908.     }
  909.  
  910.     $list_args['echo'] = false;
  911.     $list_args['title_li'] = '';
  912.     $menu .= str_replace( array( "\r", "\n", "\t" ), '', wp_list_pages($list_args) );
  913.  
  914.     if ( $menu )
  915.         $menu = '<ul>' . $menu . '</ul>';
  916.  
  917.     $menu = '<div class="' . esc_attr($args['menu_class']) . '">' . $menu . "</div>\n";
  918.     $menu = apply_filters( 'wp_page_menu', $menu, $args );
  919.     if ( $args['echo'] )
  920.         echo $menu;
  921.     else
  922.         return $menu;
  923. }
  924.  
  925. //
  926. // Page helpers
  927. //
  928.  
  929. /**
  930.  * Retrieve HTML list content for page list.
  931.  *
  932.  * @uses Walker_Page to create HTML list content.
  933.  * @since 2.1.0
  934.  * @see Walker_Page::walk() for parameters and return description.
  935.  */
  936. function walk_page_tree($pages, $depth, $current_page, $r) {
  937.     if ( empty($r['walker']) )
  938.         $walker = new Walker_Page;
  939.     else
  940.         $walker = $r['walker'];
  941.  
  942.     $args = array($pages, $depth, $r, $current_page);
  943.     return call_user_func_array(array(&$walker, 'walk'), $args);
  944. }
  945.  
  946. /**
  947.  * Retrieve HTML dropdown (select) content for page list.
  948.  *
  949.  * @uses Walker_PageDropdown to create HTML dropdown content.
  950.  * @since 2.1.0
  951.  * @see Walker_PageDropdown::walk() for parameters and return description.
  952.  */
  953. function walk_page_dropdown_tree() {
  954.     $args = func_get_args();
  955.     if ( empty($args[2]['walker']) ) // the user's options are the third parameter
  956.         $walker = new Walker_PageDropdown;
  957.     else
  958.         $walker = $args[2]['walker'];
  959.  
  960.     return call_user_func_array(array(&$walker, 'walk'), $args);
  961. }
  962.  
  963. /**
  964.  * Create HTML list of pages.
  965.  *
  966.  * @package WordPress
  967.  * @since 2.1.0
  968.  * @uses Walker
  969.  */
  970. class Walker_Page extends Walker {
  971.     /**
  972.      * @see Walker::$tree_type
  973.      * @since 2.1.0
  974.      * @var string
  975.      */
  976.     var $tree_type = 'page';
  977.  
  978.     /**
  979.      * @see Walker::$db_fields
  980.      * @since 2.1.0
  981.      * @todo Decouple this.
  982.      * @var array
  983.      */
  984.     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
  985.  
  986.     /**
  987.      * @see Walker::start_lvl()
  988.      * @since 2.1.0
  989.      *
  990.      * @param string $output Passed by reference. Used to append additional content.
  991.      * @param int $depth Depth of page. Used for padding.
  992.      */
  993.     function start_lvl(&$output, $depth) {
  994.         $indent = str_repeat("\t", $depth);
  995.         $output .= "\n$indent<ul class='children'>\n";
  996.     }
  997.  
  998.     /**
  999.      * @see Walker::end_lvl()
  1000.      * @since 2.1.0
  1001.      *
  1002.      * @param string $output Passed by reference. Used to append additional content.
  1003.      * @param int $depth Depth of page. Used for padding.
  1004.      */
  1005.     function end_lvl(&$output, $depth) {
  1006.         $indent = str_repeat("\t", $depth);
  1007.         $output .= "$indent</ul>\n";
  1008.     }
  1009.  
  1010.     /**
  1011.      * @see Walker::start_el()
  1012.      * @since 2.1.0
  1013.      *
  1014.      * @param string $output Passed by reference. Used to append additional content.
  1015.      * @param object $page Page data object.
  1016.      * @param int $depth Depth of page. Used for padding.
  1017.      * @param int $current_page Page ID.
  1018.      * @param array $args
  1019.      */
  1020.     function start_el(&$output, $page, $depth, $args, $current_page) {
  1021.         if ( $depth )
  1022.             $indent = str_repeat("\t", $depth);
  1023.         else
  1024.             $indent = '';
  1025.  
  1026.         extract($args, EXTR_SKIP);
  1027.         $css_class = array('page_item', 'page-item-'.$page->ID);
  1028.         if ( !empty($current_page) ) {
  1029.             $_current_page = get_page( $current_page );
  1030.             _get_post_ancestors($_current_page);
  1031.             if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
  1032.                 $css_class[] = 'current_page_ancestor';
  1033.             if ( $page->ID == $current_page )
  1034.                 $css_class[] = 'current_page_item';
  1035.             elseif ( $_current_page && $page->ID == $_current_page->post_parent )
  1036.                 $css_class[] = 'current_page_parent';
  1037.         } elseif ( $page->ID == get_option('page_for_posts') ) {
  1038.             $css_class[] = 'current_page_parent';
  1039.         }
  1040.  
  1041.         $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));
  1042.  
  1043.         $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_permalink($page->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
  1044.  
  1045.         if ( !empty($show_date) ) {
  1046.             if ( 'modified' == $show_date )
  1047.                 $time = $page->post_modified;
  1048.             else
  1049.                 $time = $page->post_date;
  1050.  
  1051.             $output .= " " . mysql2date($date_format, $time);
  1052.         }
  1053.     }
  1054.  
  1055.     /**
  1056.      * @see Walker::end_el()
  1057.      * @since 2.1.0
  1058.      *
  1059.      * @param string $output Passed by reference. Used to append additional content.
  1060.      * @param object $page Page data object. Not used.
  1061.      * @param int $depth Depth of page. Not Used.
  1062.      */
  1063.     function end_el(&$output, $page, $depth) {
  1064.         $output .= "</li>\n";
  1065.     }
  1066.  
  1067. }
  1068.  
  1069. /**
  1070.  * Create HTML dropdown list of pages.
  1071.  *
  1072.  * @package WordPress
  1073.  * @since 2.1.0
  1074.  * @uses Walker
  1075.  */
  1076. class Walker_PageDropdown extends Walker {
  1077.     /**
  1078.      * @see Walker::$tree_type
  1079.      * @since 2.1.0
  1080.      * @var string
  1081.      */
  1082.     var $tree_type = 'page';
  1083.  
  1084.     /**
  1085.      * @see Walker::$db_fields
  1086.      * @since 2.1.0
  1087.      * @todo Decouple this
  1088.      * @var array
  1089.      */
  1090.     var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
  1091.  
  1092.     /**
  1093.      * @see Walker::start_el()
  1094.      * @since 2.1.0
  1095.      *
  1096.      * @param string $output Passed by reference. Used to append additional content.
  1097.      * @param object $page Page data object.
  1098.      * @param int $depth Depth of page in reference to parent pages. Used for padding.
  1099.      * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
  1100.      */
  1101.     function start_el(&$output, $page, $depth, $args) {
  1102.         $pad = str_repeat('&nbsp;', $depth * 3);
  1103.  
  1104.         $output .= "\t<option class=\"level-$depth\" value=\"$page->ID\"";
  1105.         if ( $page->ID == $args['selected'] )
  1106.             $output .= ' selected="selected"';
  1107.         $output .= '>';
  1108.         $title = apply_filters( 'list_pages', $page->post_title );
  1109.         $output .= $pad . esc_html( $title );
  1110.         $output .= "</option>\n";
  1111.     }
  1112. }
  1113.  
  1114. //
  1115. // Attachments
  1116. //
  1117.  
  1118. /**
  1119.  * Display an attachment page link using an image or icon.
  1120.  *
  1121.  * @since 2.0.0
  1122.  *
  1123.  * @param int $id Optional. Post ID.
  1124.  * @param bool $fullsize Optional, default is false. Whether to use full size.
  1125.  * @param bool $deprecated Deprecated. Not used.
  1126.  * @param bool $permalink Optional, default is false. Whether to include permalink.
  1127.  */
  1128. function the_attachment_link( $id = 0, $fullsize = false, $deprecated = false, $permalink = false ) {
  1129.     if ( !empty( $deprecated ) )
  1130.         _deprecated_argument( __FUNCTION__, '2.5' );
  1131.  
  1132.     if ( $fullsize )
  1133.         echo wp_get_attachment_link($id, 'full', $permalink);
  1134.     else
  1135.         echo wp_get_attachment_link($id, 'thumbnail', $permalink);
  1136. }
  1137.  
  1138. /**
  1139.  * Retrieve an attachment page link using an image or icon, if possible.
  1140.  *
  1141.  * @since 2.5.0
  1142.  * @uses apply_filters() Calls 'wp_get_attachment_link' filter on HTML content with same parameters as function.
  1143.  *
  1144.  * @param int $id Optional. Post ID.
  1145.  * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string.
  1146.  * @param bool $permalink Optional, default is false. Whether to add permalink to image.
  1147.  * @param bool $icon Optional, default is false. Whether to include icon.
  1148.  * @param string $text Optional, default is false. If string, then will be link text.
  1149.  * @return string HTML content.
  1150.  */
  1151. function wp_get_attachment_link($id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false) {
  1152.     $id = intval($id);
  1153.     $_post = & get_post( $id );
  1154.  
  1155.     if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
  1156.         return __('Missing Attachment');
  1157.  
  1158.     if ( $permalink )
  1159.         $url = get_attachment_link($_post->ID);
  1160.  
  1161.     $post_title = esc_attr($_post->post_title);
  1162.  
  1163.     if ( $text ) {
  1164.         $link_text = esc_attr($text);
  1165.     } elseif ( ( is_int($size) && $size != 0 ) or ( is_string($size) && $size != 'none' ) or $size != false ) {
  1166.         $link_text = wp_get_attachment_image($id, $size, $icon);
  1167.     } else {
  1168.         $link_text = '';
  1169.     }
  1170.  
  1171.     if( trim($link_text) == '' )
  1172.         $link_text = $_post->post_title;
  1173.  
  1174.     return apply_filters( 'wp_get_attachment_link', "<a href='$url' title='$post_title'>$link_text</a>", $id, $size, $permalink, $icon, $text );
  1175. }
  1176.  
  1177. /**
  1178.  * Wrap attachment in <<p>> element before content.
  1179.  *
  1180.  * @since 2.0.0
  1181.  * @uses apply_filters() Calls 'prepend_attachment' hook on HTML content.
  1182.  *
  1183.  * @param string $content
  1184.  * @return string
  1185.  */
  1186. function prepend_attachment($content) {
  1187.     global $post;
  1188.  
  1189.     if ( empty($post->post_type) || $post->post_type != 'attachment' )
  1190.         return $content;
  1191.  
  1192.     $p = '<p class="attachment">';
  1193.     // show the medium sized image representation of the attachment if available, and link to the raw file
  1194.     $p .= wp_get_attachment_link(0, 'medium', false);
  1195.     $p .= '</p>';
  1196.     $p = apply_filters('prepend_attachment', $p);
  1197.  
  1198.     return "$p\n$content";
  1199. }
  1200.  
  1201. //
  1202. // Misc
  1203. //
  1204.  
  1205. /**
  1206.  * Retrieve protected post password form content.
  1207.  *
  1208.  * @since 1.0.0
  1209.  * @uses apply_filters() Calls 'the_password_form' filter on output.
  1210.  *
  1211.  * @return string HTML content for password form for password protected post.
  1212.  */
  1213. function get_the_password_form() {
  1214.     global $post;
  1215.     $label = 'pwbox-'.(empty($post->ID) ? rand() : $post->ID);
  1216.     $output = '<form action="' . get_option('siteurl') . '/wp-pass.php" method="post">
  1217.     <p>' . __("This post is password protected. To view it please enter your password below:") . '</p>
  1218.     <p><label for="' . $label . '">' . __("Password:") . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr__("Submit") . '" /></p>
  1219.     </form>
  1220.     ';
  1221.     return apply_filters('the_password_form', $output);
  1222. }
  1223.  
  1224. /**
  1225.  * Whether currently in a page template.
  1226.  *
  1227.  * This template tag allows you to determine if you are in a page template.
  1228.  * You can optionally provide a template name and then the check will be
  1229.  * specific to that template.
  1230.  *
  1231.  * @since 2.5.0
  1232.  * @uses $wp_query
  1233.  *
  1234.  * @param string $template The specific template name if specific matching is required.
  1235.  * @return bool False on failure, true if success.
  1236.  */
  1237. function is_page_template($template = '') {
  1238.     if (!is_page()) {
  1239.         return false;
  1240.     }
  1241.  
  1242.     global $wp_query;
  1243.  
  1244.     $page = $wp_query->get_queried_object();
  1245.     $custom_fields = get_post_custom_values('_wp_page_template',$page->ID);
  1246.     $page_template = $custom_fields[0];
  1247.  
  1248.     // We have no argument passed so just see if a page_template has been specified
  1249.     if ( empty( $template ) ) {
  1250.         if ( !empty( $page_template ) and ( 'default' != $page_template ) ) {
  1251.             return true;
  1252.         }
  1253.     } elseif ( $template == $page_template) {
  1254.         return true;
  1255.     }
  1256.  
  1257.     return false;
  1258. }
  1259.  
  1260. /**
  1261.  * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
  1262.  *
  1263.  * @package WordPress
  1264.  * @subpackage Post_Revisions
  1265.  * @since 2.6.0
  1266.  *
  1267.  * @uses date_i18n()
  1268.  *
  1269.  * @param int|object $revision Revision ID or revision object.
  1270.  * @param bool $link Optional, default is true. Link to revisions's page?
  1271.  * @return string i18n formatted datetimestamp or localized 'Current Revision'.
  1272.  */
  1273. function wp_post_revision_title( $revision, $link = true ) {
  1274.     if ( !$revision = get_post( $revision ) )
  1275.         return $revision;
  1276.  
  1277.     if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
  1278.         return false;
  1279.  
  1280.     /* translators: revision date format, see http://php.net/date */
  1281.     $datef = _x( 'j F, Y @ G:i', 'revision date format');
  1282.     /* translators: 1: date */
  1283.     $autosavef = __( '%1$s [Autosave]' );
  1284.     /* translators: 1: date */
  1285.     $currentf  = __( '%1$s [Current Revision]' );
  1286.  
  1287.     $date = date_i18n( $datef, strtotime( $revision->post_modified ) );
  1288.     if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
  1289.         $date = "<a href='$link'>$date</a>";
  1290.  
  1291.     if ( !wp_is_post_revision( $revision ) )
  1292.         $date = sprintf( $currentf, $date );
  1293.     elseif ( wp_is_post_autosave( $revision ) )
  1294.         $date = sprintf( $autosavef, $date );
  1295.  
  1296.     return $date;
  1297. }
  1298.  
  1299. /**
  1300.  * Display list of a post's revisions.
  1301.  *
  1302.  * Can output either a UL with edit links or a TABLE with diff interface, and
  1303.  * restore action links.
  1304.  *
  1305.  * Second argument controls parameters:
  1306.  *   (bool)   parent : include the parent (the "Current Revision") in the list.
  1307.  *   (string) format : 'list' or 'form-table'.  'list' outputs UL, 'form-table'
  1308.  *                     outputs TABLE with UI.
  1309.  *   (int)    right  : what revision is currently being viewed - used in
  1310.  *                     form-table format.
  1311.  *   (int)    left   : what revision is currently being diffed against right -
  1312.  *                     used in form-table format.
  1313.  *
  1314.  * @package WordPress
  1315.  * @subpackage Post_Revisions
  1316.  * @since 2.6.0
  1317.  *
  1318.  * @uses wp_get_post_revisions()
  1319.  * @uses wp_post_revision_title()
  1320.  * @uses get_edit_post_link()
  1321.  * @uses get_the_author_meta()
  1322.  *
  1323.  * @todo split into two functions (list, form-table) ?
  1324.  *
  1325.  * @param int|object $post_id Post ID or post object.
  1326.  * @param string|array $args See description {@link wp_parse_args()}.
  1327.  * @return null
  1328.  */
  1329. function wp_list_post_revisions( $post_id = 0, $args = null ) {
  1330.     if ( !$post = get_post( $post_id ) )
  1331.         return;
  1332.  
  1333.     $defaults = array( 'parent' => false, 'right' => false, 'left' => false, 'format' => 'list', 'type' => 'all' );
  1334.     extract( wp_parse_args( $args, $defaults ), EXTR_SKIP );
  1335.  
  1336.     switch ( $type ) {
  1337.         case 'autosave' :
  1338.             if ( !$autosave = wp_get_post_autosave( $post->ID ) )
  1339.                 return;
  1340.             $revisions = array( $autosave );
  1341.             break;
  1342.         case 'revision' : // just revisions - remove autosave later
  1343.         case 'all' :
  1344.         default :
  1345.             if ( !$revisions = wp_get_post_revisions( $post->ID ) )
  1346.                 return;
  1347.             break;
  1348.     }
  1349.  
  1350.     /* translators: post revision: 1: when, 2: author name */
  1351.     $titlef = _x( '%1$s by %2$s', 'post revision' );
  1352.  
  1353.     if ( $parent )
  1354.         array_unshift( $revisions, $post );
  1355.  
  1356.     $rows = $right_checked = '';
  1357.     $class = false;
  1358.     $can_edit_post = current_user_can( 'edit_post', $post->ID );
  1359.     foreach ( $revisions as $revision ) {
  1360.         if ( !current_user_can( 'read_post', $revision->ID ) )
  1361.             continue;
  1362.         if ( 'revision' === $type && wp_is_post_autosave( $revision ) )
  1363.             continue;
  1364.  
  1365.         $date = wp_post_revision_title( $revision );
  1366.         $name = get_the_author_meta( 'display_name', $revision->post_author );
  1367.  
  1368.         if ( 'form-table' == $format ) {
  1369.             if ( $left )
  1370.                 $left_checked = $left == $revision->ID ? ' checked="checked"' : '';
  1371.             else
  1372.                 $left_checked = $right_checked ? ' checked="checked"' : ''; // [sic] (the next one)
  1373.             $right_checked = $right == $revision->ID ? ' checked="checked"' : '';
  1374.  
  1375.             $class = $class ? '' : " class='alternate'";
  1376.  
  1377.             if ( $post->ID != $revision->ID && $can_edit_post )
  1378.                 $actions = '<a href="' . wp_nonce_url( add_query_arg( array( 'revision' => $revision->ID, 'action' => 'restore' ) ), "restore-post_$post->ID|$revision->ID" ) . '">' . __( 'Restore' ) . '</a>';
  1379.             else
  1380.                 $actions = '';
  1381.  
  1382.             $rows .= "<tr$class>\n";
  1383.             $rows .= "\t<th style='white-space: nowrap' scope='row'><input type='radio' name='left' value='$revision->ID'$left_checked /></th>\n";
  1384.             $rows .= "\t<th style='white-space: nowrap' scope='row'><input type='radio' name='right' value='$revision->ID'$right_checked /></th>\n";
  1385.             $rows .= "\t<td>$date</td>\n";
  1386.             $rows .= "\t<td>$name</td>\n";
  1387.             $rows .= "\t<td class='action-links'>$actions</td>\n";
  1388.             $rows .= "</tr>\n";
  1389.         } else {
  1390.             $title = sprintf( $titlef, $date, $name );
  1391.             $rows .= "\t<li>$title</li>\n";
  1392.         }
  1393.     }
  1394.  
  1395.     if ( 'form-table' == $format ) : ?>
  1396.  
  1397. <form action="revision.php" method="get">
  1398.  
  1399. <div class="tablenav">
  1400.     <div class="alignleft">
  1401.         <input type="submit" class="button-secondary" value="<?php esc_attr_e( 'Compare Revisions' ); ?>" />
  1402.         <input type="hidden" name="action" value="diff" />
  1403.         <input type="hidden" name="post_type" value="<?php echo esc_attr($post->post_type); ?>" />
  1404.     </div>
  1405. </div>
  1406.  
  1407. <br class="clear" />
  1408.  
  1409. <table class="widefat post-revisions" cellspacing="0" id="post-revisions">
  1410.     <col />
  1411.     <col />
  1412.     <col style="width: 33%" />
  1413.     <col style="width: 33%" />
  1414.     <col style="width: 33%" />
  1415. <thead>
  1416. <tr>
  1417.     <th scope="col"><?php /* translators: column name in revisons */ _ex( 'Old', 'revisions column name' ); ?></th>
  1418.     <th scope="col"><?php /* translators: column name in revisons */ _ex( 'New', 'revisions column name' ); ?></th>
  1419.     <th scope="col"><?php /* translators: column name in revisons */ _ex( 'Date Created', 'revisions column name' ); ?></th>
  1420.     <th scope="col"><?php _e( 'Author' ); ?></th>
  1421.     <th scope="col" class="action-links"><?php _e( 'Actions' ); ?></th>
  1422. </tr>
  1423. </thead>
  1424. <tbody>
  1425.  
  1426. <?php echo $rows; ?>
  1427.  
  1428. </tbody>
  1429. </table>
  1430.  
  1431. </form>
  1432.  
  1433. <?php
  1434.     else :
  1435.         echo "<ul class='post-revisions'>\n";
  1436.         echo $rows;
  1437.         echo "</ul>";
  1438.     endif;
  1439.  
  1440. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement