/wp-includes/post-template.php

  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. * Retrieve the ID of the current item in the WordPress Loop. 
  21. * 
  22. * @since 2.1.0 
  23. * 
  24. * @return int|false The ID of the current item in the WordPress Loop. False if $post is not set. 
  25. */ 
  26. function get_the_ID() { 
  27. $post = get_post(); 
  28. return ! empty( $post ) ? $post->ID : false; 
  29.  
  30. /** 
  31. * Display or retrieve the current post title with optional markup. 
  32. * 
  33. * @since 0.71 
  34. * 
  35. * @param string $before Optional. Markup to prepend to the title. Default empty. 
  36. * @param string $after Optional. Markup to append to the title. Default empty. 
  37. * @param bool $echo Optional. Whether to echo or return the title. Default true for echo. 
  38. * @return string|void Current post title if $echo is false. 
  39. */ 
  40. function the_title( $before = '', $after = '', $echo = true ) { 
  41. $title = get_the_title(); 
  42.  
  43. if ( strlen($title) == 0 ) 
  44. return; 
  45.  
  46. $title = $before . $title . $after; 
  47.  
  48. if ( $echo ) 
  49. echo $title; 
  50. else 
  51. return $title; 
  52.  
  53. /** 
  54. * Sanitize the current title when retrieving or displaying. 
  55. * 
  56. * Works like the_title(), except the parameters can be in a string or 
  57. * an array. See the function for what can be override in the $args parameter. 
  58. * 
  59. * The title before it is displayed will have the tags stripped and esc_attr() 
  60. * before it is passed to the user or displayed. The default as with the_title(),  
  61. * is to display the title. 
  62. * 
  63. * @since 2.3.0 
  64. * 
  65. * @param string|array $args { 
  66. * Title attribute arguments. Optional. 
  67. * 
  68. * @type string $before Markup to prepend to the title. Default empty. 
  69. * @type string $after Markup to append to the title. Default empty. 
  70. * @type bool $echo Whether to echo or return the title. Default true for echo. 
  71. * @type WP_Post $post Current post object to retrieve the title for. 
  72. * } 
  73. * @return string|void String when echo is false. 
  74. */ 
  75. function the_title_attribute( $args = '' ) { 
  76. $defaults = array( 'before' => '', 'after' => '', 'echo' => true, 'post' => get_post() ); 
  77. $r = wp_parse_args( $args, $defaults ); 
  78.  
  79. $title = get_the_title( $r['post'] ); 
  80.  
  81. if ( strlen( $title ) == 0 ) { 
  82. return; 
  83.  
  84. $title = $r['before'] . $title . $r['after']; 
  85. $title = esc_attr( strip_tags( $title ) ); 
  86.  
  87. if ( $r['echo'] ) { 
  88. echo $title; 
  89. } else { 
  90. return $title; 
  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|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 
  102. * @return string 
  103. */ 
  104. function get_the_title( $post = 0 ) { 
  105. $post = get_post( $post ); 
  106.  
  107. $title = isset( $post->post_title ) ? $post->post_title : ''; 
  108. $id = isset( $post->ID ) ? $post->ID : 0; 
  109.  
  110. if ( ! is_admin() ) { 
  111. if ( ! empty( $post->post_password ) ) { 
  112.  
  113. /** 
  114. * Filters the text prepended to the post title for protected posts. 
  115. * 
  116. * The filter is only applied on the front end. 
  117. * 
  118. * @since 2.8.0 
  119. * 
  120. * @param string $prepend Text displayed before the post title. 
  121. * Default 'Protected: %s'. 
  122. * @param WP_Post $post Current post object. 
  123. */ 
  124. $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ), $post ); 
  125. $title = sprintf( $protected_title_format, $title ); 
  126. } elseif ( isset( $post->post_status ) && 'private' == $post->post_status ) { 
  127.  
  128. /** 
  129. * Filters the text prepended to the post title of private posts. 
  130. * 
  131. * The filter is only applied on the front end. 
  132. * 
  133. * @since 2.8.0 
  134. * 
  135. * @param string $prepend Text displayed before the post title. 
  136. * Default 'Private: %s'. 
  137. * @param WP_Post $post Current post object. 
  138. */ 
  139. $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s' ), $post ); 
  140. $title = sprintf( $private_title_format, $title ); 
  141.  
  142. /** 
  143. * Filters the post title. 
  144. * 
  145. * @since 0.71 
  146. * 
  147. * @param string $title The post title. 
  148. * @param int $id The post ID. 
  149. */ 
  150. return apply_filters( 'the_title', $title, $id ); 
  151.  
  152. /** 
  153. * Display the Post Global Unique Identifier (guid). 
  154. * 
  155. * The guid will appear to be a link, but should not be used as a link to the 
  156. * post. The reason you should not use it as a link, is because of moving the 
  157. * blog across domains. 
  158. * 
  159. * URL is escaped to make it XML-safe. 
  160. * 
  161. * @since 1.5.0 
  162. * 
  163. * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post. 
  164. */ 
  165. function the_guid( $post = 0 ) { 
  166. $post = get_post( $post ); 
  167.  
  168. $guid = isset( $post->guid ) ? get_the_guid( $post ) : ''; 
  169. $id = isset( $post->ID ) ? $post->ID : 0; 
  170.  
  171. /** 
  172. * Filters the escaped Global Unique Identifier (guid) of the post. 
  173. * 
  174. * @since 4.2.0 
  175. * 
  176. * @see get_the_guid() 
  177. * 
  178. * @param string $guid Escaped Global Unique Identifier (guid) of the post. 
  179. * @param int $id The post ID. 
  180. */ 
  181. echo apply_filters( 'the_guid', $guid, $id ); 
  182.  
  183. /** 
  184. * Retrieve the Post Global Unique Identifier (guid). 
  185. * 
  186. * The guid will appear to be a link, but should not be used as an link to the 
  187. * post. The reason you should not use it as a link, is because of moving the 
  188. * blog across domains. 
  189. * 
  190. * @since 1.5.0 
  191. * 
  192. * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post. 
  193. * @return string 
  194. */ 
  195. function get_the_guid( $post = 0 ) { 
  196. $post = get_post( $post ); 
  197.  
  198. $guid = isset( $post->guid ) ? $post->guid : ''; 
  199. $id = isset( $post->ID ) ? $post->ID : 0; 
  200.  
  201. /** 
  202. * Filters the Global Unique Identifier (guid) of the post. 
  203. * 
  204. * @since 1.5.0 
  205. * 
  206. * @param string $guid Global Unique Identifier (guid) of the post. 
  207. * @param int $id The post ID. 
  208. */ 
  209. return apply_filters( 'get_the_guid', $guid, $id ); 
  210.  
  211. /** 
  212. * Display the post content. 
  213. * 
  214. * @since 0.71 
  215. * 
  216. * @param string $more_link_text Optional. Content for when there is more text. 
  217. * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false. 
  218. */ 
  219. function the_content( $more_link_text = null, $strip_teaser = false) { 
  220. $content = get_the_content( $more_link_text, $strip_teaser ); 
  221.  
  222. /** 
  223. * Filters the post content. 
  224. * 
  225. * @since 0.71 
  226. * 
  227. * @param string $content Content of the current post. 
  228. */ 
  229. $content = apply_filters( 'the_content', $content ); 
  230. $content = str_replace( ']]>', ']]>', $content ); 
  231. echo $content; 
  232.  
  233. /** 
  234. * Retrieve the post content. 
  235. * 
  236. * @since 0.71 
  237. * 
  238. * @global int $page Page number of a single post/page. 
  239. * @global int $more Boolean indicator for whether single post/page is being viewed. 
  240. * @global bool $preview Whether post/page is in preview mode. 
  241. * @global array $pages Array of all pages in post/page. Each array element contains part of the content separated by the <!--nextpage--> tag. 
  242. * @global int $multipage Boolean indicator for whether multiple pages are in play. 
  243. * 
  244. * @param string $more_link_text Optional. Content for when there is more text. 
  245. * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false. 
  246. * @return string 
  247. */ 
  248. function get_the_content( $more_link_text = null, $strip_teaser = false ) { 
  249. global $page, $more, $preview, $pages, $multipage; 
  250.  
  251. $post = get_post(); 
  252.  
  253. if ( null === $more_link_text ) { 
  254. $more_link_text = sprintf( 
  255. '<span aria-label="%1$s">%2$s</span>',  
  256. sprintf( 
  257. /** translators: %s: Name of current post */ 
  258. __( 'Continue reading %s' ),  
  259. the_title_attribute( array( 'echo' => false ) ) 
  260. ),  
  261. __( '(more…)' ) 
  262. ); 
  263.  
  264. $output = ''; 
  265. $has_teaser = false; 
  266.  
  267. // If post password required and it doesn't match the cookie. 
  268. if ( post_password_required( $post ) ) 
  269. return get_the_password_form( $post ); 
  270.  
  271. if ( $page > count( $pages ) ) // if the requested page doesn't exist 
  272. $page = count( $pages ); // give them the highest numbered page that DOES exist 
  273.  
  274. $content = $pages[$page - 1]; 
  275. if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) { 
  276. $content = explode( $matches[0], $content, 2 ); 
  277. if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) ) 
  278. $more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) ); 
  279.  
  280. $has_teaser = true; 
  281. } else { 
  282. $content = array( $content ); 
  283.  
  284. if ( false !== strpos( $post->post_content, '<!--noteaser-->' ) && ( ! $multipage || $page == 1 ) ) 
  285. $strip_teaser = true; 
  286.  
  287. $teaser = $content[0]; 
  288.  
  289. if ( $more && $strip_teaser && $has_teaser ) 
  290. $teaser = ''; 
  291.  
  292. $output .= $teaser; 
  293.  
  294. if ( count( $content ) > 1 ) { 
  295. if ( $more ) { 
  296. $output .= '<span id="more-' . $post->ID . '"></span>' . $content[1]; 
  297. } else { 
  298. if ( ! empty( $more_link_text ) ) 
  299.  
  300. /** 
  301. * Filters the Read More link text. 
  302. * 
  303. * @since 2.8.0 
  304. * 
  305. * @param string $more_link_element Read More link element. 
  306. * @param string $more_link_text Read More text. 
  307. */ 
  308. $output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text ); 
  309. $output = force_balance_tags( $output ); 
  310.  
  311. if ( $preview ) // Preview fix for JavaScript bug with foreign languages. 
  312. $output = preg_replace_callback( '/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output ); 
  313.  
  314. return $output; 
  315.  
  316. /** 
  317. * Preview fix for JavaScript bug with foreign languages. 
  318. * 
  319. * @since 3.1.0 
  320. * @access private 
  321. * 
  322. * @param array $match Match array from preg_replace_callback. 
  323. * @return string 
  324. */ 
  325. function _convert_urlencoded_to_entities( $match ) { 
  326. return '&#' . base_convert( $match[1], 16, 10 ) . ';'; 
  327.  
  328. /** 
  329. * Display the post excerpt. 
  330. * 
  331. * @since 0.71 
  332. */ 
  333. function the_excerpt() { 
  334.  
  335. /** 
  336. * Filters the displayed post excerpt. 
  337. * 
  338. * @since 0.71 
  339. * 
  340. * @see get_the_excerpt() 
  341. * 
  342. * @param string $post_excerpt The post excerpt. 
  343. */ 
  344. echo apply_filters( 'the_excerpt', get_the_excerpt() ); 
  345.  
  346. /** 
  347. * Retrieves the post excerpt. 
  348. * 
  349. * @since 0.71 
  350. * @since 4.5.0 Introduced the `$post` parameter. 
  351. * 
  352. * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 
  353. * @return string Post excerpt. 
  354. */ 
  355. function get_the_excerpt( $post = null ) { 
  356. if ( is_bool( $post ) ) { 
  357. _deprecated_argument( __FUNCTION__, '2.3.0' ); 
  358.  
  359. $post = get_post( $post ); 
  360. if ( empty( $post ) ) { 
  361. return ''; 
  362.  
  363. if ( post_password_required( $post ) ) { 
  364. return __( 'There is no excerpt because this is a protected post.' ); 
  365.  
  366. /** 
  367. * Filters the retrieved post excerpt. 
  368. * 
  369. * @since 1.2.0 
  370. * @since 4.5.0 Introduced the `$post` parameter. 
  371. * 
  372. * @param string $post_excerpt The post excerpt. 
  373. * @param WP_Post $post Post object. 
  374. */ 
  375. return apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); 
  376.  
  377. /** 
  378. * Whether post has excerpt. 
  379. * 
  380. * @since 2.3.0 
  381. * 
  382. * @param int|WP_Post $id Optional. Post ID or post object. 
  383. * @return bool 
  384. */ 
  385. function has_excerpt( $id = 0 ) { 
  386. $post = get_post( $id ); 
  387. return ( !empty( $post->post_excerpt ) ); 
  388.  
  389. /** 
  390. * Display the classes for the post div. 
  391. * 
  392. * @since 2.7.0 
  393. * 
  394. * @param string|array $class One or more classes to add to the class list. 
  395. * @param int|WP_Post $post_id Optional. Post ID or post object. Defaults to the global `$post`. 
  396. */ 
  397. function post_class( $class = '', $post_id = null ) { 
  398. // Separates classes with a single space, collates classes for post DIV 
  399. echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"'; 
  400.  
  401. /** 
  402. * Retrieves the classes for the post div as an array. 
  403. * 
  404. * The class names are many. If the post is a sticky, then the 'sticky' 
  405. * class name. The class 'hentry' is always added to each post. If the post has a 
  406. * post thumbnail, 'has-post-thumbnail' is added as a class. For each taxonomy that 
  407. * the post belongs to, a class will be added of the format '{$taxonomy}-{$slug}' - 
  408. * eg 'category-foo' or 'my_custom_taxonomy-bar'. 
  409. * 
  410. * The 'post_tag' taxonomy is a special 
  411. * case; the class has the 'tag-' prefix instead of 'post_tag-'. All classes are 
  412. * passed through the filter, {@see 'post_class'}, with the list of classes, followed by 
  413. * $class parameter value, with the post ID as the last parameter. 
  414. * 
  415. * @since 2.7.0 
  416. * @since 4.2.0 Custom taxonomy classes were added. 
  417. * 
  418. * @param string|array $class One or more classes to add to the class list. 
  419. * @param int|WP_Post $post_id Optional. Post ID or post object. 
  420. * @return array Array of classes. 
  421. */ 
  422. function get_post_class( $class = '', $post_id = null ) { 
  423. $post = get_post( $post_id ); 
  424.  
  425. $classes = array(); 
  426.  
  427. if ( $class ) { 
  428. if ( ! is_array( $class ) ) { 
  429. $class = preg_split( '#\s+#', $class ); 
  430. $classes = array_map( 'esc_attr', $class ); 
  431. } else { 
  432. // Ensure that we always coerce class to being an array. 
  433. $class = array(); 
  434.  
  435. if ( ! $post ) { 
  436. return $classes; 
  437.  
  438. $classes[] = 'post-' . $post->ID; 
  439. if ( ! is_admin() ) 
  440. $classes[] = $post->post_type; 
  441. $classes[] = 'type-' . $post->post_type; 
  442. $classes[] = 'status-' . $post->post_status; 
  443.  
  444. // Post Format 
  445. if ( post_type_supports( $post->post_type, 'post-formats' ) ) { 
  446. $post_format = get_post_format( $post->ID ); 
  447.  
  448. if ( $post_format && !is_wp_error($post_format) ) 
  449. $classes[] = 'format-' . sanitize_html_class( $post_format ); 
  450. else 
  451. $classes[] = 'format-standard'; 
  452.  
  453. $post_password_required = post_password_required( $post->ID ); 
  454.  
  455. // Post requires password. 
  456. if ( $post_password_required ) { 
  457. $classes[] = 'post-password-required'; 
  458. } elseif ( ! empty( $post->post_password ) ) { 
  459. $classes[] = 'post-password-protected'; 
  460.  
  461. // Post thumbnails. 
  462. if ( current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) && ! is_attachment( $post ) && ! $post_password_required ) { 
  463. $classes[] = 'has-post-thumbnail'; 
  464.  
  465. // sticky for Sticky Posts 
  466. if ( is_sticky( $post->ID ) ) { 
  467. if ( is_home() && ! is_paged() ) { 
  468. $classes[] = 'sticky'; 
  469. } elseif ( is_admin() ) { 
  470. $classes[] = 'status-sticky'; 
  471.  
  472. // hentry for hAtom compliance 
  473. $classes[] = 'hentry'; 
  474.  
  475. // All public taxonomies 
  476. $taxonomies = get_taxonomies( array( 'public' => true ) ); 
  477. foreach ( (array) $taxonomies as $taxonomy ) { 
  478. if ( is_object_in_taxonomy( $post->post_type, $taxonomy ) ) { 
  479. foreach ( (array) get_the_terms( $post->ID, $taxonomy ) as $term ) { 
  480. if ( empty( $term->slug ) ) { 
  481. continue; 
  482.  
  483. $term_class = sanitize_html_class( $term->slug, $term->term_id ); 
  484. if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) { 
  485. $term_class = $term->term_id; 
  486.  
  487. // 'post_tag' uses the 'tag' prefix for backward compatibility. 
  488. if ( 'post_tag' == $taxonomy ) { 
  489. $classes[] = 'tag-' . $term_class; 
  490. } else { 
  491. $classes[] = sanitize_html_class( $taxonomy . '-' . $term_class, $taxonomy . '-' . $term->term_id ); 
  492.  
  493. $classes = array_map( 'esc_attr', $classes ); 
  494.  
  495. /** 
  496. * Filters the list of CSS classes for the current post. 
  497. * 
  498. * @since 2.7.0 
  499. * 
  500. * @param array $classes An array of post classes. 
  501. * @param array $class An array of additional classes added to the post. 
  502. * @param int $post_id The post ID. 
  503. */ 
  504. $classes = apply_filters( 'post_class', $classes, $class, $post->ID ); 
  505.  
  506. return array_unique( $classes ); 
  507.  
  508. /** 
  509. * Display the classes for the body element. 
  510. * 
  511. * @since 2.8.0 
  512. * 
  513. * @param string|array $class One or more classes to add to the class list. 
  514. */ 
  515. function body_class( $class = '' ) { 
  516. // Separates classes with a single space, collates classes for body element 
  517. echo 'class="' . join( ' ', get_body_class( $class ) ) . '"'; 
  518.  
  519. /** 
  520. * Retrieve the classes for the body element as an array. 
  521. * 
  522. * @since 2.8.0 
  523. * 
  524. * @global WP_Query $wp_query 
  525. * 
  526. * @param string|array $class One or more classes to add to the class list. 
  527. * @return array Array of classes. 
  528. */ 
  529. function get_body_class( $class = '' ) { 
  530. global $wp_query; 
  531.  
  532. $classes = array(); 
  533.  
  534. if ( is_rtl() ) 
  535. $classes[] = 'rtl'; 
  536.  
  537. if ( is_front_page() ) 
  538. $classes[] = 'home'; 
  539. if ( is_home() ) 
  540. $classes[] = 'blog'; 
  541. if ( is_archive() ) 
  542. $classes[] = 'archive'; 
  543. if ( is_date() ) 
  544. $classes[] = 'date'; 
  545. if ( is_search() ) { 
  546. $classes[] = 'search'; 
  547. $classes[] = $wp_query->posts ? 'search-results' : 'search-no-results'; 
  548. if ( is_paged() ) 
  549. $classes[] = 'paged'; 
  550. if ( is_attachment() ) 
  551. $classes[] = 'attachment'; 
  552. if ( is_404() ) 
  553. $classes[] = 'error404'; 
  554.  
  555. if ( is_singular() ) { 
  556. $post_id = $wp_query->get_queried_object_id(); 
  557. $post = $wp_query->get_queried_object(); 
  558. $post_type = $post->post_type; 
  559.  
  560. if ( is_page_template() ) { 
  561. $classes[] = "{$post_type}-template"; 
  562.  
  563. $template_slug = get_page_template_slug( $post_id ); 
  564. $template_parts = explode( '/', $template_slug ); 
  565.  
  566. foreach ( $template_parts as $part ) { 
  567. $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) ); 
  568. $classes[] = "{$post_type}-template-" . sanitize_html_class( str_replace( '.', '-', $template_slug ) ); 
  569. } else { 
  570. $classes[] = "{$post_type}-template-default"; 
  571.  
  572. if ( is_single() ) { 
  573. $classes[] = 'single'; 
  574. if ( isset( $post->post_type ) ) { 
  575. $classes[] = 'single-' . sanitize_html_class( $post->post_type, $post_id ); 
  576. $classes[] = 'postid-' . $post_id; 
  577.  
  578. // Post Format 
  579. if ( post_type_supports( $post->post_type, 'post-formats' ) ) { 
  580. $post_format = get_post_format( $post->ID ); 
  581.  
  582. if ( $post_format && !is_wp_error($post_format) ) 
  583. $classes[] = 'single-format-' . sanitize_html_class( $post_format ); 
  584. else 
  585. $classes[] = 'single-format-standard'; 
  586.  
  587. if ( is_attachment() ) { 
  588. $mime_type = get_post_mime_type($post_id); 
  589. $mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' ); 
  590. $classes[] = 'attachmentid-' . $post_id; 
  591. $classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type ); 
  592. } elseif ( is_page() ) { 
  593. $classes[] = 'page'; 
  594.  
  595. $page_id = $wp_query->get_queried_object_id(); 
  596.  
  597. $post = get_post($page_id); 
  598.  
  599. $classes[] = 'page-id-' . $page_id; 
  600.  
  601. if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) { 
  602. $classes[] = 'page-parent'; 
  603.  
  604. if ( $post->post_parent ) { 
  605. $classes[] = 'page-child'; 
  606. $classes[] = 'parent-pageid-' . $post->post_parent; 
  607. } elseif ( is_archive() ) { 
  608. if ( is_post_type_archive() ) { 
  609. $classes[] = 'post-type-archive'; 
  610. $post_type = get_query_var( 'post_type' ); 
  611. if ( is_array( $post_type ) ) 
  612. $post_type = reset( $post_type ); 
  613. $classes[] = 'post-type-archive-' . sanitize_html_class( $post_type ); 
  614. } elseif ( is_author() ) { 
  615. $author = $wp_query->get_queried_object(); 
  616. $classes[] = 'author'; 
  617. if ( isset( $author->user_nicename ) ) { 
  618. $classes[] = 'author-' . sanitize_html_class( $author->user_nicename, $author->ID ); 
  619. $classes[] = 'author-' . $author->ID; 
  620. } elseif ( is_category() ) { 
  621. $cat = $wp_query->get_queried_object(); 
  622. $classes[] = 'category'; 
  623. if ( isset( $cat->term_id ) ) { 
  624. $cat_class = sanitize_html_class( $cat->slug, $cat->term_id ); 
  625. if ( is_numeric( $cat_class ) || ! trim( $cat_class, '-' ) ) { 
  626. $cat_class = $cat->term_id; 
  627.  
  628. $classes[] = 'category-' . $cat_class; 
  629. $classes[] = 'category-' . $cat->term_id; 
  630. } elseif ( is_tag() ) { 
  631. $tag = $wp_query->get_queried_object(); 
  632. $classes[] = 'tag'; 
  633. if ( isset( $tag->term_id ) ) { 
  634. $tag_class = sanitize_html_class( $tag->slug, $tag->term_id ); 
  635. if ( is_numeric( $tag_class ) || ! trim( $tag_class, '-' ) ) { 
  636. $tag_class = $tag->term_id; 
  637.  
  638. $classes[] = 'tag-' . $tag_class; 
  639. $classes[] = 'tag-' . $tag->term_id; 
  640. } elseif ( is_tax() ) { 
  641. $term = $wp_query->get_queried_object(); 
  642. if ( isset( $term->term_id ) ) { 
  643. $term_class = sanitize_html_class( $term->slug, $term->term_id ); 
  644. if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) { 
  645. $term_class = $term->term_id; 
  646.  
  647. $classes[] = 'tax-' . sanitize_html_class( $term->taxonomy ); 
  648. $classes[] = 'term-' . $term_class; 
  649. $classes[] = 'term-' . $term->term_id; 
  650.  
  651. if ( is_user_logged_in() ) 
  652. $classes[] = 'logged-in'; 
  653.  
  654. if ( is_admin_bar_showing() ) { 
  655. $classes[] = 'admin-bar'; 
  656. $classes[] = 'no-customize-support'; 
  657.  
  658. if ( get_background_color() !== get_theme_support( 'custom-background', 'default-color' ) || get_background_image() ) 
  659. $classes[] = 'custom-background'; 
  660.  
  661. if ( has_custom_logo() ) { 
  662. $classes[] = 'wp-custom-logo'; 
  663.  
  664. $page = $wp_query->get( 'page' ); 
  665.  
  666. if ( ! $page || $page < 2 ) 
  667. $page = $wp_query->get( 'paged' ); 
  668.  
  669. if ( $page && $page > 1 && ! is_404() ) { 
  670. $classes[] = 'paged-' . $page; 
  671.  
  672. if ( is_single() ) 
  673. $classes[] = 'single-paged-' . $page; 
  674. elseif ( is_page() ) 
  675. $classes[] = 'page-paged-' . $page; 
  676. elseif ( is_category() ) 
  677. $classes[] = 'category-paged-' . $page; 
  678. elseif ( is_tag() ) 
  679. $classes[] = 'tag-paged-' . $page; 
  680. elseif ( is_date() ) 
  681. $classes[] = 'date-paged-' . $page; 
  682. elseif ( is_author() ) 
  683. $classes[] = 'author-paged-' . $page; 
  684. elseif ( is_search() ) 
  685. $classes[] = 'search-paged-' . $page; 
  686. elseif ( is_post_type_archive() ) 
  687. $classes[] = 'post-type-paged-' . $page; 
  688.  
  689. if ( ! empty( $class ) ) { 
  690. if ( !is_array( $class ) ) 
  691. $class = preg_split( '#\s+#', $class ); 
  692. $classes = array_merge( $classes, $class ); 
  693. } else { 
  694. // Ensure that we always coerce class to being an array. 
  695. $class = array(); 
  696.  
  697. $classes = array_map( 'esc_attr', $classes ); 
  698.  
  699. /** 
  700. * Filters the list of CSS body classes for the current post or page. 
  701. * 
  702. * @since 2.8.0 
  703. * 
  704. * @param array $classes An array of body classes. 
  705. * @param array $class An array of additional classes added to the body. 
  706. */ 
  707. $classes = apply_filters( 'body_class', $classes, $class ); 
  708.  
  709. return array_unique( $classes ); 
  710.  
  711. /** 
  712. * Whether post requires password and correct password has been provided. 
  713. * 
  714. * @since 2.7.0 
  715. * 
  716. * @param int|WP_Post|null $post An optional post. Global $post used if not provided. 
  717. * @return bool false if a password is not required or the correct password cookie is present, true otherwise. 
  718. */ 
  719. function post_password_required( $post = null ) { 
  720. $post = get_post($post); 
  721.  
  722. if ( empty( $post->post_password ) ) { 
  723. /** This filter is documented in wp-includes/post.php */ 
  724. return apply_filters( 'post_password_required', false, $post ); 
  725.  
  726. if ( ! isset( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) ) { 
  727. /** This filter is documented in wp-includes/post.php */ 
  728. return apply_filters( 'post_password_required', true, $post ); 
  729.  
  730. $hasher = new PasswordHash( 8, true ); 
  731.  
  732. $hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ); 
  733. if ( 0 !== strpos( $hash, '$P$B' ) ) { 
  734. $required = true; 
  735. } else { 
  736. $required = ! $hasher->CheckPassword( $post->post_password, $hash ); 
  737.  
  738. /** 
  739. * Filters whether a post requires the user to supply a password. 
  740. * 
  741. * @since 4.7.0 
  742. * 
  743. * @param bool $required Whether the user needs to supply a password. True if password has not been 
  744. * provided or is incorrect, false if password has been supplied or is not required. 
  745. * @param WP_Post $post Post data. 
  746. */ 
  747. return apply_filters( 'post_password_required', $required, $post ); 
  748.  
  749. // 
  750. // Page Template Functions for usage in Themes 
  751. // 
  752.   
  753. /** 
  754. * The formatted output of a list of pages. 
  755. * 
  756. * Displays page links for paginated posts (i.e. includes the <!--nextpage-->. 
  757. * Quicktag one or more times). This tag must be within The Loop. 
  758. * 
  759. * @since 1.2.0 
  760. * 
  761. * @global int $page 
  762. * @global int $numpages 
  763. * @global int $multipage 
  764. * @global int $more 
  765. * 
  766. * @param string|array $args { 
  767. * Optional. Array or string of default arguments. 
  768. * 
  769. * @type string $before HTML or text to prepend to each link. Default is `<p> Pages:`. 
  770. * @type string $after HTML or text to append to each link. Default is `</p>`. 
  771. * @type string $link_before HTML or text to prepend to each link, inside the `<a>` tag. 
  772. * Also prepended to the current item, which is not linked. Default empty. 
  773. * @type string $link_after HTML or text to append to each Pages link inside the `<a>` tag. 
  774. * Also appended to the current item, which is not linked. Default empty. 
  775. * @type string $next_or_number Indicates whether page numbers should be used. Valid values are number 
  776. * and next. Default is 'number'. 
  777. * @type string $separator Text between pagination links. Default is ' '. 
  778. * @type string $nextpagelink Link text for the next page link, if available. Default is 'Next Page'. 
  779. * @type string $previouspagelink Link text for the previous page link, if available. Default is 'Previous Page'. 
  780. * @type string $pagelink Format string for page numbers. The % in the parameter string will be 
  781. * replaced with the page number, so 'Page %' generates "Page 1", "Page 2", etc. 
  782. * Defaults to '%', just the page number. 
  783. * @type int|bool $echo Whether to echo or not. Accepts 1|true or 0|false. Default 1|true. 
  784. * } 
  785. * @return string Formatted output in HTML. 
  786. */ 
  787. function wp_link_pages( $args = '' ) { 
  788. global $page, $numpages, $multipage, $more; 
  789.  
  790. $defaults = array( 
  791. 'before' => '<p>' . __( 'Pages:' ),  
  792. 'after' => '</p>',  
  793. 'link_before' => '',  
  794. 'link_after' => '',  
  795. 'next_or_number' => 'number',  
  796. 'separator' => ' ',  
  797. 'nextpagelink' => __( 'Next page' ),  
  798. 'previouspagelink' => __( 'Previous page' ),  
  799. 'pagelink' => '%',  
  800. 'echo' => 1 
  801. ); 
  802.  
  803. $params = wp_parse_args( $args, $defaults ); 
  804.  
  805. /** 
  806. * Filters the arguments used in retrieving page links for paginated posts. 
  807. * 
  808. * @since 3.0.0 
  809. * 
  810. * @param array $params An array of arguments for page links for paginated posts. 
  811. */ 
  812. $r = apply_filters( 'wp_link_pages_args', $params ); 
  813.  
  814. $output = ''; 
  815. if ( $multipage ) { 
  816. if ( 'number' == $r['next_or_number'] ) { 
  817. $output .= $r['before']; 
  818. for ( $i = 1; $i <= $numpages; $i++ ) { 
  819. $link = $r['link_before'] . str_replace( '%', $i, $r['pagelink'] ) . $r['link_after']; 
  820. if ( $i != $page || ! $more && 1 == $page ) { 
  821. $link = _wp_link_page( $i ) . $link . '</a>'; 
  822. /** 
  823. * Filters the HTML output of individual page number links. 
  824. * 
  825. * @since 3.6.0 
  826. * 
  827. * @param string $link The page number HTML output. 
  828. * @param int $i Page number for paginated posts' page links. 
  829. */ 
  830. $link = apply_filters( 'wp_link_pages_link', $link, $i ); 
  831.  
  832. // Use the custom links separator beginning with the second link. 
  833. $output .= ( 1 === $i ) ? ' ' : $r['separator']; 
  834. $output .= $link; 
  835. $output .= $r['after']; 
  836. } elseif ( $more ) { 
  837. $output .= $r['before']; 
  838. $prev = $page - 1; 
  839. if ( $prev > 0 ) { 
  840. $link = _wp_link_page( $prev ) . $r['link_before'] . $r['previouspagelink'] . $r['link_after'] . '</a>'; 
  841.  
  842. /** This filter is documented in wp-includes/post-template.php */ 
  843. $output .= apply_filters( 'wp_link_pages_link', $link, $prev ); 
  844. $next = $page + 1; 
  845. if ( $next <= $numpages ) { 
  846. if ( $prev ) { 
  847. $output .= $r['separator']; 
  848. $link = _wp_link_page( $next ) . $r['link_before'] . $r['nextpagelink'] . $r['link_after'] . '</a>'; 
  849.  
  850. /** This filter is documented in wp-includes/post-template.php */ 
  851. $output .= apply_filters( 'wp_link_pages_link', $link, $next ); 
  852. $output .= $r['after']; 
  853.  
  854. /** 
  855. * Filters the HTML output of page links for paginated posts. 
  856. * 
  857. * @since 3.6.0 
  858. * 
  859. * @param string $output HTML output of paginated posts' page links. 
  860. * @param array $args An array of arguments. 
  861. */ 
  862. $html = apply_filters( 'wp_link_pages', $output, $args ); 
  863.  
  864. if ( $r['echo'] ) { 
  865. echo $html; 
  866. return $html; 
  867.  
  868. /** 
  869. * Helper function for wp_link_pages(). 
  870. * 
  871. * @since 3.1.0 
  872. * @access private 
  873. * 
  874. * @global WP_Rewrite $wp_rewrite 
  875. * 
  876. * @param int $i Page number. 
  877. * @return string Link. 
  878. */ 
  879. function _wp_link_page( $i ) { 
  880. global $wp_rewrite; 
  881. $post = get_post(); 
  882. $query_args = array(); 
  883.  
  884. if ( 1 == $i ) { 
  885. $url = get_permalink(); 
  886. } else { 
  887. if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) ) 
  888. $url = add_query_arg( 'page', $i, get_permalink() ); 
  889. elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') == $post->ID ) 
  890. $url = trailingslashit(get_permalink()) . user_trailingslashit("$wp_rewrite->pagination_base/" . $i, 'single_paged'); 
  891. else 
  892. $url = trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged'); 
  893.  
  894. if ( is_preview() ) { 
  895.  
  896. if ( ( 'draft' !== $post->post_status ) && isset( $_GET['preview_id'], $_GET['preview_nonce'] ) ) { 
  897. $query_args['preview_id'] = wp_unslash( $_GET['preview_id'] ); 
  898. $query_args['preview_nonce'] = wp_unslash( $_GET['preview_nonce'] ); 
  899.  
  900. $url = get_preview_post_link( $post, $query_args, $url ); 
  901.  
  902. return '<a href="' . esc_url( $url ) . '">'; 
  903.  
  904. // 
  905.  // Post-meta: Custom per-post fields. 
  906. // 
  907.   
  908. /** 
  909. * Retrieve post custom meta data field. 
  910. * 
  911. * @since 1.5.0 
  912. * 
  913. * @param string $key Meta data key name. 
  914. * @return false|string|array Array of values or single value, if only one element exists. False will be returned if key does not exist. 
  915. */ 
  916. function post_custom( $key = '' ) { 
  917. $custom = get_post_custom(); 
  918.  
  919. if ( !isset( $custom[$key] ) ) 
  920. return false; 
  921. elseif ( 1 == count($custom[$key]) ) 
  922. return $custom[$key][0]; 
  923. else 
  924. return $custom[$key]; 
  925.  
  926. /** 
  927. * Display list of post custom fields. 
  928. * 
  929. * @since 1.2.0 
  930. * 
  931. * @internal This will probably change at some point... 
  932. * 
  933. */ 
  934. function the_meta() { 
  935. if ( $keys = get_post_custom_keys() ) { 
  936. echo "<ul class='post-meta'>\n"; 
  937. foreach ( (array) $keys as $key ) { 
  938. $keyt = trim($key); 
  939. if ( is_protected_meta( $keyt, 'post' ) ) 
  940. continue; 
  941. $values = array_map('trim', get_post_custom_values($key)); 
  942. $value = implode($values, ', '); 
  943.  
  944. /** 
  945. * Filters the HTML output of the li element in the post custom fields list. 
  946. * 
  947. * @since 2.2.0 
  948. * 
  949. * @param string $html The HTML output for the li element. 
  950. * @param string $key Meta key. 
  951. * @param string $value Meta value. 
  952. */ 
  953. echo apply_filters( 'the_meta_key', "<li><span class='post-meta-key'>$key:</span> $value</li>\n", $key, $value ); 
  954. echo "</ul>\n"; 
  955.  
  956. // 
  957.  // Pages 
  958. // 
  959.   
  960. /** 
  961. * Retrieve or display list of pages as a dropdown (select list). 
  962. * 
  963. * @since 2.1.0 
  964. * @since 4.2.0 The `$value_field` argument was added. 
  965. * @since 4.3.0 The `$class` argument was added. 
  966. * 
  967. * @param array|string $args { 
  968. * Optional. Array or string of arguments to generate a pages drop-down element. 
  969. * 
  970. * @type int $depth Maximum depth. Default 0. 
  971. * @type int $child_of Page ID to retrieve child pages of. Default 0. 
  972. * @type int|string $selected Value of the option that should be selected. Default 0. 
  973. * @type bool|int $echo Whether to echo or return the generated markup. Accepts 0, 1,  
  974. * or their bool equivalents. Default 1. 
  975. * @type string $name Value for the 'name' attribute of the select element. 
  976. * Default 'page_id'. 
  977. * @type string $id Value for the 'id' attribute of the select element. 
  978. * @type string $class Value for the 'class' attribute of the select element. Default: none. 
  979. * Defaults to the value of `$name`. 
  980. * @type string $show_option_none Text to display for showing no pages. Default empty (does not display). 
  981. * @type string $show_option_no_change Text to display for "no change" option. Default empty (does not display). 
  982. * @type string $option_none_value Value to use when no page is selected. Default empty. 
  983. * @type string $value_field Post field used to populate the 'value' attribute of the option 
  984. * elements. Accepts any valid post field. Default 'ID'. 
  985. * } 
  986. * @return string HTML content, if not displaying. 
  987. */ 
  988. function wp_dropdown_pages( $args = '' ) { 
  989. $defaults = array( 
  990. 'depth' => 0, 'child_of' => 0,  
  991. 'selected' => 0, 'echo' => 1,  
  992. 'name' => 'page_id', 'id' => '',  
  993. 'class' => '',  
  994. 'show_option_none' => '', 'show_option_no_change' => '',  
  995. 'option_none_value' => '',  
  996. 'value_field' => 'ID',  
  997. ); 
  998.  
  999. $r = wp_parse_args( $args, $defaults ); 
  1000.  
  1001. $pages = get_pages( $r ); 
  1002. $output = ''; 
  1003. // Back-compat with old system where both id and name were based on $name argument 
  1004. if ( empty( $r['id'] ) ) { 
  1005. $r['id'] = $r['name']; 
  1006.  
  1007. if ( ! empty( $pages ) ) { 
  1008. $class = ''; 
  1009. if ( ! empty( $r['class'] ) ) { 
  1010. $class = " class='" . esc_attr( $r['class'] ) . "'"; 
  1011.  
  1012. $output = "<select name='" . esc_attr( $r['name'] ) . "'" . $class . " id='" . esc_attr( $r['id'] ) . "'>\n"; 
  1013. if ( $r['show_option_no_change'] ) { 
  1014. $output .= "\t<option value=\"-1\">" . $r['show_option_no_change'] . "</option>\n"; 
  1015. if ( $r['show_option_none'] ) { 
  1016. $output .= "\t<option value=\"" . esc_attr( $r['option_none_value'] ) . '">' . $r['show_option_none'] . "</option>\n"; 
  1017. $output .= walk_page_dropdown_tree( $pages, $r['depth'], $r ); 
  1018. $output .= "</select>\n"; 
  1019.  
  1020. /** 
  1021. * Filters the HTML output of a list of pages as a drop down. 
  1022. * 
  1023. * @since 2.1.0 
  1024. * @since 4.4.0 `$r` and `$pages` added as arguments. 
  1025. * 
  1026. * @param string $output HTML output for drop down list of pages. 
  1027. * @param array $r The parsed arguments array. 
  1028. * @param array $pages List of WP_Post objects returned by `get_pages()` 
  1029. */ 
  1030. $html = apply_filters( 'wp_dropdown_pages', $output, $r, $pages ); 
  1031.  
  1032. if ( $r['echo'] ) { 
  1033. echo $html; 
  1034. return $html; 
  1035.  
  1036. /** 
  1037. * Retrieve or display list of pages in list (li) format. 
  1038. * 
  1039. * @since 1.5.0 
  1040. * @since 4.7.0 Added the `item_spacing` argument. 
  1041. * 
  1042. * @see get_pages() 
  1043. * 
  1044. * @global WP_Query $wp_query 
  1045. * 
  1046. * @param array|string $args { 
  1047. * Array or string of arguments. Optional. 
  1048. * 
  1049. * @type int $child_of Display only the sub-pages of a single page by ID. Default 0 (all pages). 
  1050. * @type string $authors Comma-separated list of author IDs. Default empty (all authors). 
  1051. * @type string $date_format PHP date format to use for the listed pages. Relies on the 'show_date' parameter. 
  1052. * Default is the value of 'date_format' option. 
  1053. * @type int $depth Number of levels in the hierarchy of pages to include in the generated list. 
  1054. * Accepts -1 (any depth), 0 (all pages), 1 (top-level pages only), and n (pages to 
  1055. * the given n depth). Default 0. 
  1056. * @type bool $echo Whether or not to echo the list of pages. Default true. 
  1057. * @type string $exclude Comma-separated list of page IDs to exclude. Default empty. 
  1058. * @type array $include Comma-separated list of page IDs to include. Default empty. 
  1059. * @type string $link_after Text or HTML to follow the page link label. Default null. 
  1060. * @type string $link_before Text or HTML to precede the page link label. Default null. 
  1061. * @type string $post_type Post type to query for. Default 'page'. 
  1062. * @type string|array $post_status Comma-separated list or array of post statuses to include. Default 'publish'. 
  1063. * @type string $show_date Whether to display the page publish or modified date for each page. Accepts 
  1064. * 'modified' or any other value. An empty value hides the date. Default empty. 
  1065. * @type string $sort_column Comma-separated list of column names to sort the pages by. Accepts 'post_author',  
  1066. * 'post_date', 'post_title', 'post_name', 'post_modified', 'post_modified_gmt',  
  1067. * 'menu_order', 'post_parent', 'ID', 'rand', or 'comment_count'. Default 'post_title'. 
  1068. * @type string $title_li List heading. Passing a null or empty value will result in no heading, and the list 
  1069. * will not be wrapped with unordered list `<ul>` tags. Default 'Pages'. 
  1070. * @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. 
  1071. * Default 'preserve'. 
  1072. * @type Walker $walker Walker instance to use for listing pages. Default empty (Walker_Page). 
  1073. * } 
  1074. * @return string|void HTML list of pages. 
  1075. */ 
  1076. function wp_list_pages( $args = '' ) { 
  1077. $defaults = array( 
  1078. 'depth' => 0,  
  1079. 'show_date' => '',  
  1080. 'date_format' => get_option( 'date_format' ),  
  1081. 'child_of' => 0,  
  1082. 'exclude' => '',  
  1083. 'title_li' => __( 'Pages' ),  
  1084. 'echo' => 1,  
  1085. 'authors' => '',  
  1086. 'sort_column' => 'menu_order, post_title',  
  1087. 'link_before' => '',  
  1088. 'link_after' => '',  
  1089. 'item_spacing' => 'preserve',  
  1090. 'walker' => '',  
  1091. ); 
  1092.  
  1093. $r = wp_parse_args( $args, $defaults ); 
  1094.  
  1095. if ( ! in_array( $r['item_spacing'], array( 'preserve', 'discard' ), true ) ) { 
  1096. // invalid value, fall back to default. 
  1097. $r['item_spacing'] = $defaults['item_spacing']; 
  1098.  
  1099. $output = ''; 
  1100. $current_page = 0; 
  1101.  
  1102. // sanitize, mostly to keep spaces out 
  1103. $r['exclude'] = preg_replace( '/[^0-9, ]/', '', $r['exclude'] ); 
  1104.  
  1105. // Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array) 
  1106. $exclude_array = ( $r['exclude'] ) ? explode( ', ', $r['exclude'] ) : array(); 
  1107.  
  1108. /** 
  1109. * Filters the array of pages to exclude from the pages list. 
  1110. * 
  1111. * @since 2.1.0 
  1112. * 
  1113. * @param array $exclude_array An array of page IDs to exclude. 
  1114. */ 
  1115. $r['exclude'] = implode( ', ', apply_filters( 'wp_list_pages_excludes', $exclude_array ) ); 
  1116.  
  1117. // Query pages. 
  1118. $r['hierarchical'] = 0; 
  1119. $pages = get_pages( $r ); 
  1120.  
  1121. if ( ! empty( $pages ) ) { 
  1122. if ( $r['title_li'] ) { 
  1123. $output .= '<li class="pagenav">' . $r['title_li'] . '<ul>'; 
  1124. global $wp_query; 
  1125. if ( is_page() || is_attachment() || $wp_query->is_posts_page ) { 
  1126. $current_page = get_queried_object_id(); 
  1127. } elseif ( is_singular() ) { 
  1128. $queried_object = get_queried_object(); 
  1129. if ( is_post_type_hierarchical( $queried_object->post_type ) ) { 
  1130. $current_page = $queried_object->ID; 
  1131.  
  1132. $output .= walk_page_tree( $pages, $r['depth'], $current_page, $r ); 
  1133.  
  1134. if ( $r['title_li'] ) { 
  1135. $output .= '</ul></li>'; 
  1136.  
  1137. /** 
  1138. * Filters the HTML output of the pages to list. 
  1139. * 
  1140. * @since 1.5.1 
  1141. * @since 4.4.0 `$pages` added as arguments. 
  1142. * 
  1143. * @see wp_list_pages() 
  1144. * 
  1145. * @param string $output HTML output of the pages list. 
  1146. * @param array $r An array of page-listing arguments. 
  1147. * @param array $pages List of WP_Post objects returned by `get_pages()` 
  1148. */ 
  1149. $html = apply_filters( 'wp_list_pages', $output, $r, $pages ); 
  1150.  
  1151. if ( $r['echo'] ) { 
  1152. echo $html; 
  1153. } else { 
  1154. return $html; 
  1155.  
  1156. /** 
  1157. * Displays or retrieves a list of pages with an optional home link. 
  1158. * 
  1159. * The arguments are listed below and part of the arguments are for wp_list_pages()} function. 
  1160. * Check that function for more info on those arguments. 
  1161. * 
  1162. * @since 2.7.0 
  1163. * @since 4.4.0 Added `menu_id`, `container`, `before`, `after`, and `walker` arguments. 
  1164. * @since 4.7.0 Added the `item_spacing` argument. 
  1165. * 
  1166. * @param array|string $args { 
  1167. * Optional. Arguments to generate a page menu. See wp_list_pages() for additional arguments. 
  1168. * 
  1169. * @type string $sort_column How to short the list of pages. Accepts post column names. 
  1170. * Default 'menu_order, post_title'. 
  1171. * @type string $menu_id ID for the div containing the page list. Default is empty string. 
  1172. * @type string $menu_class Class to use for the element containing the page list. Default 'menu'. 
  1173. * @type string $container Element to use for the element containing the page list. Default 'div'. 
  1174. * @type bool $echo Whether to echo the list or return it. Accepts true (echo) or false (return). 
  1175. * Default true. 
  1176. * @type int|bool|string $show_home Whether to display the link to the home page. Can just enter the text 
  1177. * you'd like shown for the home link. 1|true defaults to 'Home'. 
  1178. * @type string $link_before The HTML or text to prepend to $show_home text. Default empty. 
  1179. * @type string $link_after The HTML or text to append to $show_home text. Default empty. 
  1180. * @type string $before The HTML or text to prepend to the menu. Default is '<ul>'. 
  1181. * @type string $after The HTML or text to append to the menu. Default is '</ul>'. 
  1182. * @type string $item_spacing Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'discard'. 
  1183. * @type Walker $walker Walker instance to use for listing pages. Default empty (Walker_Page). 
  1184. * } 
  1185. * @return string|void HTML menu 
  1186. */ 
  1187. function wp_page_menu( $args = array() ) { 
  1188. $defaults = array( 
  1189. 'sort_column' => 'menu_order, post_title',  
  1190. 'menu_id' => '',  
  1191. 'menu_class' => 'menu',  
  1192. 'container' => 'div',  
  1193. 'echo' => true,  
  1194. 'link_before' => '',  
  1195. 'link_after' => '',  
  1196. 'before' => '<ul>',  
  1197. 'after' => '</ul>',  
  1198. 'item_spacing' => 'discard',  
  1199. 'walker' => '',  
  1200. ); 
  1201. $args = wp_parse_args( $args, $defaults ); 
  1202.  
  1203. if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ) ) ) { 
  1204. // invalid value, fall back to default. 
  1205. $args['item_spacing'] = $defaults['item_spacing']; 
  1206.  
  1207. if ( 'preserve' === $args['item_spacing'] ) { 
  1208. $t = "\t"; 
  1209. $n = "\n"; 
  1210. } else { 
  1211. $t = ''; 
  1212. $n = ''; 
  1213.  
  1214. /** 
  1215. * Filters the arguments used to generate a page-based menu. 
  1216. * 
  1217. * @since 2.7.0 
  1218. * 
  1219. * @see wp_page_menu() 
  1220. * 
  1221. * @param array $args An array of page menu arguments. 
  1222. */ 
  1223. $args = apply_filters( 'wp_page_menu_args', $args ); 
  1224.  
  1225. $menu = ''; 
  1226.  
  1227. $list_args = $args; 
  1228.  
  1229. // Show Home in the menu 
  1230. if ( ! empty($args['show_home']) ) { 
  1231. if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] ) 
  1232. $text = __('Home'); 
  1233. else 
  1234. $text = $args['show_home']; 
  1235. $class = ''; 
  1236. if ( is_front_page() && !is_paged() ) 
  1237. $class = 'class="current_page_item"'; 
  1238. $menu .= '<li ' . $class . '><a href="' . home_url( '/' ) . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>'; 
  1239. // If the front page is a page, add it to the exclude list 
  1240. if (get_option('show_on_front') == 'page') { 
  1241. if ( !empty( $list_args['exclude'] ) ) { 
  1242. $list_args['exclude'] .= ', '; 
  1243. } else { 
  1244. $list_args['exclude'] = ''; 
  1245. $list_args['exclude'] .= get_option('page_on_front'); 
  1246.  
  1247. $list_args['echo'] = false; 
  1248. $list_args['title_li'] = ''; 
  1249. $menu .= wp_list_pages( $list_args ); 
  1250.  
  1251. $container = sanitize_text_field( $args['container'] ); 
  1252.  
  1253. // Fallback in case `wp_nav_menu()` was called without a container. 
  1254. if ( empty( $container ) ) { 
  1255. $container = 'div'; 
  1256.  
  1257. if ( $menu ) { 
  1258.  
  1259. // wp_nav_menu doesn't set before and after 
  1260. if ( isset( $args['fallback_cb'] ) && 
  1261. 'wp_page_menu' === $args['fallback_cb'] && 
  1262. 'ul' !== $container ) { 
  1263. $args['before'] = "<ul>{$n}"; 
  1264. $args['after'] = '</ul>'; 
  1265.  
  1266. $menu = $args['before'] . $menu . $args['after']; 
  1267.  
  1268. $attrs = ''; 
  1269. if ( ! empty( $args['menu_id'] ) ) { 
  1270. $attrs .= ' id="' . esc_attr( $args['menu_id'] ) . '"'; 
  1271.  
  1272. if ( ! empty( $args['menu_class'] ) ) { 
  1273. $attrs .= ' class="' . esc_attr( $args['menu_class'] ) . '"'; 
  1274.  
  1275. $menu = "<{$container}{$attrs}>" . $menu . "</{$container}>{$n}"; 
  1276.  
  1277. /** 
  1278. * Filters the HTML output of a page-based menu. 
  1279. * 
  1280. * @since 2.7.0 
  1281. * 
  1282. * @see wp_page_menu() 
  1283. * 
  1284. * @param string $menu The HTML output. 
  1285. * @param array $args An array of arguments. 
  1286. */ 
  1287. $menu = apply_filters( 'wp_page_menu', $menu, $args ); 
  1288. if ( $args['echo'] ) 
  1289. echo $menu; 
  1290. else 
  1291. return $menu; 
  1292.  
  1293. // 
  1294.  // Page helpers 
  1295. // 
  1296.   
  1297. /** 
  1298. * Retrieve HTML list content for page list. 
  1299. * 
  1300. * @uses Walker_Page to create HTML list content. 
  1301. * @since 2.1.0 
  1302. * 
  1303. * @param array $pages 
  1304. * @param int $depth 
  1305. * @param int $current_page 
  1306. * @param array $r 
  1307. * @return string 
  1308. */ 
  1309. function walk_page_tree( $pages, $depth, $current_page, $r ) { 
  1310. if ( empty($r['walker']) ) 
  1311. $walker = new Walker_Page; 
  1312. else 
  1313. $walker = $r['walker']; 
  1314.  
  1315. foreach ( (array) $pages as $page ) { 
  1316. if ( $page->post_parent ) 
  1317. $r['pages_with_children'][ $page->post_parent ] = true; 
  1318.  
  1319. $args = array($pages, $depth, $r, $current_page); 
  1320. return call_user_func_array(array($walker, 'walk'), $args); 
  1321.  
  1322. /** 
  1323. * Retrieve HTML dropdown (select) content for page list. 
  1324. * 
  1325. * @uses Walker_PageDropdown to create HTML dropdown content. 
  1326. * @since 2.1.0 
  1327. * @see Walker_PageDropdown::walk() for parameters and return description. 
  1328. * 
  1329. * @return string 
  1330. */ 
  1331. function walk_page_dropdown_tree() { 
  1332. $args = func_get_args(); 
  1333. if ( empty($args[2]['walker']) ) // the user's options are the third parameter 
  1334. $walker = new Walker_PageDropdown; 
  1335. else 
  1336. $walker = $args[2]['walker']; 
  1337.  
  1338. return call_user_func_array(array($walker, 'walk'), $args); 
  1339.  
  1340. // 
  1341.  // Attachments 
  1342. // 
  1343.   
  1344. /** 
  1345. * Display an attachment page link using an image or icon. 
  1346. * 
  1347. * @since 2.0.0 
  1348. * 
  1349. * @param int|WP_Post $id Optional. Post ID or post object. 
  1350. * @param bool $fullsize Optional, default is false. Whether to use full size. 
  1351. * @param bool $deprecated Deprecated. Not used. 
  1352. * @param bool $permalink Optional, default is false. Whether to include permalink. 
  1353. */ 
  1354. function the_attachment_link( $id = 0, $fullsize = false, $deprecated = false, $permalink = false ) { 
  1355. if ( !empty( $deprecated ) ) 
  1356. _deprecated_argument( __FUNCTION__, '2.5.0' ); 
  1357.  
  1358. if ( $fullsize ) 
  1359. echo wp_get_attachment_link($id, 'full', $permalink); 
  1360. else 
  1361. echo wp_get_attachment_link($id, 'thumbnail', $permalink); 
  1362.  
  1363. /** 
  1364. * Retrieve an attachment page link using an image or icon, if possible. 
  1365. * 
  1366. * @since 2.5.0 
  1367. * @since 4.4.0 The `$id` parameter can now accept either a post ID or `WP_Post` object. 
  1368. * 
  1369. * @param int|WP_Post $id Optional. Post ID or post object. 
  1370. * @param string|array $size Optional. Image size. Accepts any valid image size, or an array 
  1371. * of width and height values in pixels (in that order). 
  1372. * Default 'thumbnail'. 
  1373. * @param bool $permalink Optional, Whether to add permalink to image. Default false. 
  1374. * @param bool $icon Optional. Whether the attachment is an icon. Default false. 
  1375. * @param string|false $text Optional. Link text to use. Activated by passing a string, false otherwise. 
  1376. * Default false. 
  1377. * @param array|string $attr Optional. Array or string of attributes. Default empty. 
  1378. * @return string HTML content. 
  1379. */ 
  1380. function wp_get_attachment_link( $id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false, $attr = '' ) { 
  1381. $_post = get_post( $id ); 
  1382.  
  1383. if ( empty( $_post ) || ( 'attachment' !== $_post->post_type ) || ! $url = wp_get_attachment_url( $_post->ID ) ) { 
  1384. return __( 'Missing Attachment' ); 
  1385.  
  1386. if ( $permalink ) { 
  1387. $url = get_attachment_link( $_post->ID ); 
  1388.  
  1389. if ( $text ) { 
  1390. $link_text = $text; 
  1391. } elseif ( $size && 'none' != $size ) { 
  1392. $link_text = wp_get_attachment_image( $_post->ID, $size, $icon, $attr ); 
  1393. } else { 
  1394. $link_text = ''; 
  1395.  
  1396. if ( '' === trim( $link_text ) ) { 
  1397. $link_text = $_post->post_title; 
  1398.  
  1399. if ( '' === trim( $link_text ) ) { 
  1400. $link_text = esc_html( pathinfo( get_attached_file( $_post->ID ), PATHINFO_FILENAME ) ); 
  1401. /** 
  1402. * Filters a retrieved attachment page link. 
  1403. * 
  1404. * @since 2.7.0 
  1405. * 
  1406. * @param string $link_html The page link HTML output. 
  1407. * @param int $id Post ID. 
  1408. * @param string|array $size Size of the image. Image size or array of width and height values (in that order). 
  1409. * Default 'thumbnail'. 
  1410. * @param bool $permalink Whether to add permalink to image. Default false. 
  1411. * @param bool $icon Whether to include an icon. Default false. 
  1412. * @param string|bool $text If string, will be link text. Default false. 
  1413. */ 
  1414. return apply_filters( 'wp_get_attachment_link', "<a href='" . esc_url( $url ) . "'>$link_text</a>", $id, $size, $permalink, $icon, $text ); 
  1415.  
  1416. /** 
  1417. * Wrap attachment in paragraph tag before content. 
  1418. * 
  1419. * @since 2.0.0 
  1420. * 
  1421. * @param string $content 
  1422. * @return string 
  1423. */ 
  1424. function prepend_attachment($content) { 
  1425. $post = get_post(); 
  1426.  
  1427. if ( empty($post->post_type) || $post->post_type != 'attachment' ) 
  1428. return $content; 
  1429.  
  1430. if ( wp_attachment_is( 'video', $post ) ) { 
  1431. $meta = wp_get_attachment_metadata( get_the_ID() ); 
  1432. $atts = array( 'src' => wp_get_attachment_url() ); 
  1433. if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) { 
  1434. $atts['width'] = (int) $meta['width']; 
  1435. $atts['height'] = (int) $meta['height']; 
  1436. if ( has_post_thumbnail() ) { 
  1437. $atts['poster'] = wp_get_attachment_url( get_post_thumbnail_id() ); 
  1438. $p = wp_video_shortcode( $atts ); 
  1439. } elseif ( wp_attachment_is( 'audio', $post ) ) { 
  1440. $p = wp_audio_shortcode( array( 'src' => wp_get_attachment_url() ) ); 
  1441. } else { 
  1442. $p = '<p class="attachment">'; 
  1443. // show the medium sized image representation of the attachment if available, and link to the raw file 
  1444. $p .= wp_get_attachment_link(0, 'medium', false); 
  1445. $p .= '</p>'; 
  1446.  
  1447. /** 
  1448. * Filters the attachment markup to be prepended to the post content. 
  1449. * 
  1450. * @since 2.0.0 
  1451. * 
  1452. * @see prepend_attachment() 
  1453. * 
  1454. * @param string $p The attachment HTML output. 
  1455. */ 
  1456. $p = apply_filters( 'prepend_attachment', $p ); 
  1457.  
  1458. return "$p\n$content"; 
  1459.  
  1460. // 
  1461.  // Misc 
  1462. // 
  1463.   
  1464. /** 
  1465. * Retrieve protected post password form content. 
  1466. * 
  1467. * @since 1.0.0 
  1468. * 
  1469. * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 
  1470. * @return string HTML content for password form for password protected post. 
  1471. */ 
  1472. function get_the_password_form( $post = 0 ) { 
  1473. $post = get_post( $post ); 
  1474. $label = 'pwbox-' . ( empty($post->ID) ? rand() : $post->ID ); 
  1475. $output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" class="post-password-form" method="post"> 
  1476. <p>' . __( 'This content is password protected. To view it please enter your password below:' ) . '</p> 
  1477. <p><label for="' . $label . '">' . __( 'Password:' ) . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr_x( 'Enter', 'post password form' ) . '" /></p></form> 
  1478. '; 
  1479.  
  1480. /** 
  1481. * Filters the HTML output for the protected post password form. 
  1482. * 
  1483. * If modifying the password field, please note that the core database schema 
  1484. * limits the password field to 20 characters regardless of the value of the 
  1485. * size attribute in the form input. 
  1486. * 
  1487. * @since 2.7.0 
  1488. * 
  1489. * @param string $output The password form HTML output. 
  1490. */ 
  1491. return apply_filters( 'the_password_form', $output ); 
  1492.  
  1493. /** 
  1494. * Whether currently in a page template. 
  1495. * 
  1496. * This template tag allows you to determine if you are in a page template. 
  1497. * You can optionally provide a template name or array of template names 
  1498. * and then the check will be specific to that template. 
  1499. * 
  1500. * @since 2.5.0 
  1501. * @since 4.2.0 The `$template` parameter was changed to also accept an array of page templates. 
  1502. * @since 4.7.0 Now works with any post type, not just pages. 
  1503. * 
  1504. * @param string|array $template The specific template name or array of templates to match. 
  1505. * @return bool True on success, false on failure. 
  1506. */ 
  1507. function is_page_template( $template = '' ) { 
  1508. if ( ! is_singular() ) { 
  1509. return false; 
  1510.  
  1511. $page_template = get_page_template_slug( get_queried_object_id() ); 
  1512.  
  1513. if ( empty( $template ) ) 
  1514. return (bool) $page_template; 
  1515.  
  1516. if ( $template == $page_template ) 
  1517. return true; 
  1518.  
  1519. if ( is_array( $template ) ) { 
  1520. if ( ( in_array( 'default', $template, true ) && ! $page_template ) 
  1521. || in_array( $page_template, $template, true ) 
  1522. ) { 
  1523. return true; 
  1524.  
  1525. return ( 'default' === $template && ! $page_template ); 
  1526.  
  1527. /** 
  1528. * Get the specific template name for a given post. 
  1529. * 
  1530. * @since 3.4.0 
  1531. * @since 4.7.0 Now works with any post type, not just pages. 
  1532. * 
  1533. * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 
  1534. * @return string|false Page template filename. Returns an empty string when the default page template 
  1535. * is in use. Returns false if the post does not exist. 
  1536. */ 
  1537. function get_page_template_slug( $post = null ) { 
  1538. $post = get_post( $post ); 
  1539.  
  1540. if ( ! $post ) { 
  1541. return false; 
  1542.  
  1543. $template = get_post_meta( $post->ID, '_wp_page_template', true ); 
  1544.  
  1545. if ( ! $template || 'default' == $template ) { 
  1546. return ''; 
  1547.  
  1548. return $template; 
  1549.  
  1550. /** 
  1551. * Retrieve formatted date timestamp of a revision (linked to that revisions's page). 
  1552. * 
  1553. * @since 2.6.0 
  1554. * 
  1555. * @param int|object $revision Revision ID or revision object. 
  1556. * @param bool $link Optional, default is true. Link to revisions's page? 
  1557. * @return string|false i18n formatted datetimestamp or localized 'Current Revision'. 
  1558. */ 
  1559. function wp_post_revision_title( $revision, $link = true ) { 
  1560. if ( !$revision = get_post( $revision ) ) 
  1561. return $revision; 
  1562.  
  1563. if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) ) 
  1564. return false; 
  1565.  
  1566. /** translators: revision date format, see https://secure.php.net/date */ 
  1567. $datef = _x( 'F j, Y @ H:i:s', 'revision date format' ); 
  1568. /** translators: %s: revision date */ 
  1569. $autosavef = __( '%s [Autosave]' ); 
  1570. /** translators: %s: revision date */ 
  1571. $currentf = __( '%s [Current Revision]' ); 
  1572.  
  1573. $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); 
  1574. if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) ) 
  1575. $date = "<a href='$link'>$date</a>"; 
  1576.  
  1577. if ( !wp_is_post_revision( $revision ) ) 
  1578. $date = sprintf( $currentf, $date ); 
  1579. elseif ( wp_is_post_autosave( $revision ) ) 
  1580. $date = sprintf( $autosavef, $date ); 
  1581.  
  1582. return $date; 
  1583.  
  1584. /** 
  1585. * Retrieve formatted date timestamp of a revision (linked to that revisions's page). 
  1586. * 
  1587. * @since 3.6.0 
  1588. * 
  1589. * @param int|object $revision Revision ID or revision object. 
  1590. * @param bool $link Optional, default is true. Link to revisions's page? 
  1591. * @return string|false gravatar, user, i18n formatted datetimestamp or localized 'Current Revision'. 
  1592. */ 
  1593. function wp_post_revision_title_expanded( $revision, $link = true ) { 
  1594. if ( !$revision = get_post( $revision ) ) 
  1595. return $revision; 
  1596.  
  1597. if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) ) 
  1598. return false; 
  1599.  
  1600. $author = get_the_author_meta( 'display_name', $revision->post_author ); 
  1601. /** translators: revision date format, see https://secure.php.net/date */ 
  1602. $datef = _x( 'F j, Y @ H:i:s', 'revision date format' ); 
  1603.  
  1604. $gravatar = get_avatar( $revision->post_author, 24 ); 
  1605.  
  1606. $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); 
  1607. if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) ) 
  1608. $date = "<a href='$link'>$date</a>"; 
  1609.  
  1610. $revision_date_author = sprintf( 
  1611. /** translators: post revision title: 1: author avatar, 2: author name, 3: time ago, 4: date */ 
  1612. __( '%1$s %2$s, %3$s ago (%4$s)' ),  
  1613. $gravatar,  
  1614. $author,  
  1615. human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ),  
  1616. $date 
  1617. ); 
  1618.  
  1619. /** translators: %s: revision date with author avatar */ 
  1620. $autosavef = __( '%s [Autosave]' ); 
  1621. /** translators: %s: revision date with author avatar */ 
  1622. $currentf = __( '%s [Current Revision]' ); 
  1623.  
  1624. if ( !wp_is_post_revision( $revision ) ) 
  1625. $revision_date_author = sprintf( $currentf, $revision_date_author ); 
  1626. elseif ( wp_is_post_autosave( $revision ) ) 
  1627. $revision_date_author = sprintf( $autosavef, $revision_date_author ); 
  1628.  
  1629. /** 
  1630. * Filters the formatted author and date for a revision. 
  1631. * 
  1632. * @since 4.4.0 
  1633. * 
  1634. * @param string $revision_date_author The formatted string. 
  1635. * @param WP_Post $revision The revision object. 
  1636. * @param bool $link Whether to link to the revisions page, as passed into 
  1637. * wp_post_revision_title_expanded(). 
  1638. */ 
  1639. return apply_filters( 'wp_post_revision_title_expanded', $revision_date_author, $revision, $link ); 
  1640.  
  1641. /** 
  1642. * Display list of a post's revisions. 
  1643. * 
  1644. * Can output either a UL with edit links or a TABLE with diff interface, and 
  1645. * restore action links. 
  1646. * 
  1647. * @since 2.6.0 
  1648. * 
  1649. * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post. 
  1650. * @param string $type 'all' (default), 'revision' or 'autosave' 
  1651. */ 
  1652. function wp_list_post_revisions( $post_id = 0, $type = 'all' ) { 
  1653. if ( ! $post = get_post( $post_id ) ) 
  1654. return; 
  1655.  
  1656. // $args array with (parent, format, right, left, type) deprecated since 3.6 
  1657. if ( is_array( $type ) ) { 
  1658. $type = ! empty( $type['type'] ) ? $type['type'] : $type; 
  1659. _deprecated_argument( __FUNCTION__, '3.6.0' ); 
  1660.  
  1661. if ( ! $revisions = wp_get_post_revisions( $post->ID ) ) 
  1662. return; 
  1663.  
  1664. $rows = ''; 
  1665. foreach ( $revisions as $revision ) { 
  1666. if ( ! current_user_can( 'read_post', $revision->ID ) ) 
  1667. continue; 
  1668.  
  1669. $is_autosave = wp_is_post_autosave( $revision ); 
  1670. if ( ( 'revision' === $type && $is_autosave ) || ( 'autosave' === $type && ! $is_autosave ) ) 
  1671. continue; 
  1672.  
  1673. $rows .= "\t<li>" . wp_post_revision_title_expanded( $revision ) . "</li>\n"; 
  1674.  
  1675. echo "<div class='hide-if-js'><p>" . __( 'JavaScript must be enabled to use this feature.' ) . "</p></div>\n"; 
  1676.  
  1677. echo "<ul class='post-revisions hide-if-no-js'>\n"; 
  1678. echo $rows; 
  1679. echo "</ul>"; 
.