PageRenderTime 62ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/APP/wp-includes/post-template.php

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