PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/link-template.php

http://github.com/markjaquith/WordPress
PHP | 4473 lines | 3318 code | 224 blank | 931 comment | 230 complexity | 317a745f2d5a5a23fe368a709d0a4135 MD5 | raw file
Possible License(s): 0BSD

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * WordPress Link Template Functions
  4. *
  5. * @package WordPress
  6. * @subpackage Template
  7. */
  8. /**
  9. * Displays the permalink for the current post.
  10. *
  11. * @since 1.2.0
  12. * @since 4.4.0 Added the `$post` parameter.
  13. *
  14. * @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
  15. */
  16. function the_permalink( $post = 0 ) {
  17. /**
  18. * Filters the display of the permalink for the current post.
  19. *
  20. * @since 1.5.0
  21. * @since 4.4.0 Added the `$post` parameter.
  22. *
  23. * @param string $permalink The permalink for the current post.
  24. * @param int|WP_Post $post Post ID, WP_Post object, or 0. Default 0.
  25. */
  26. echo esc_url( apply_filters( 'the_permalink', get_permalink( $post ), $post ) );
  27. }
  28. /**
  29. * Retrieves a trailing-slashed string if the site is set for adding trailing slashes.
  30. *
  31. * Conditionally adds a trailing slash if the permalink structure has a trailing
  32. * slash, strips the trailing slash if not. The string is passed through the
  33. * {@see 'user_trailingslashit'} filter. Will remove trailing slash from string, if
  34. * site is not set to have them.
  35. *
  36. * @since 2.2.0
  37. *
  38. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  39. *
  40. * @param string $string URL with or without a trailing slash.
  41. * @param string $type_of_url Optional. The type of URL being considered (e.g. single, category, etc)
  42. * for use in the filter. Default empty string.
  43. * @return string The URL with the trailing slash appended or stripped.
  44. */
  45. function user_trailingslashit( $string, $type_of_url = '' ) {
  46. global $wp_rewrite;
  47. if ( $wp_rewrite->use_trailing_slashes ) {
  48. $string = trailingslashit( $string );
  49. } else {
  50. $string = untrailingslashit( $string );
  51. }
  52. /**
  53. * Filters the trailing-slashed string, depending on whether the site is set to use trailing slashes.
  54. *
  55. * @since 2.2.0
  56. *
  57. * @param string $string URL with or without a trailing slash.
  58. * @param string $type_of_url The type of URL being considered. Accepts 'single', 'single_trackback',
  59. * 'single_feed', 'single_paged', 'commentpaged', 'paged', 'home', 'feed',
  60. * 'category', 'page', 'year', 'month', 'day', 'post_type_archive'.
  61. */
  62. return apply_filters( 'user_trailingslashit', $string, $type_of_url );
  63. }
  64. /**
  65. * Displays the permalink anchor for the current post.
  66. *
  67. * The permalink mode title will use the post title for the 'a' element 'id'
  68. * attribute. The id mode uses 'post-' with the post ID for the 'id' attribute.
  69. *
  70. * @since 0.71
  71. *
  72. * @param string $mode Optional. Permalink mode. Accepts 'title' or 'id'. Default 'id'.
  73. */
  74. function permalink_anchor( $mode = 'id' ) {
  75. $post = get_post();
  76. switch ( strtolower( $mode ) ) {
  77. case 'title':
  78. $title = sanitize_title( $post->post_title ) . '-' . $post->ID;
  79. echo '<a id="' . $title . '"></a>';
  80. break;
  81. case 'id':
  82. default:
  83. echo '<a id="post-' . $post->ID . '"></a>';
  84. break;
  85. }
  86. }
  87. /**
  88. * Retrieves the full permalink for the current post or post ID.
  89. *
  90. * This function is an alias for get_permalink().
  91. *
  92. * @since 3.9.0
  93. *
  94. * @see get_permalink()
  95. *
  96. * @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
  97. * @param bool $leavename Optional. Whether to keep post name or page name. Default false.
  98. *
  99. * @return string|false The permalink URL or false if post does not exist.
  100. */
  101. function get_the_permalink( $post = 0, $leavename = false ) {
  102. return get_permalink( $post, $leavename );
  103. }
  104. /**
  105. * Retrieves the full permalink for the current post or post ID.
  106. *
  107. * @since 1.0.0
  108. *
  109. * @param int|WP_Post $post Optional. Post ID or post object. Default is the global `$post`.
  110. * @param bool $leavename Optional. Whether to keep post name or page name. Default false.
  111. * @return string|false The permalink URL or false if post does not exist.
  112. */
  113. function get_permalink( $post = 0, $leavename = false ) {
  114. $rewritecode = array(
  115. '%year%',
  116. '%monthnum%',
  117. '%day%',
  118. '%hour%',
  119. '%minute%',
  120. '%second%',
  121. $leavename ? '' : '%postname%',
  122. '%post_id%',
  123. '%category%',
  124. '%author%',
  125. $leavename ? '' : '%pagename%',
  126. );
  127. if ( is_object( $post ) && isset( $post->filter ) && 'sample' == $post->filter ) {
  128. $sample = true;
  129. } else {
  130. $post = get_post( $post );
  131. $sample = false;
  132. }
  133. if ( empty( $post->ID ) ) {
  134. return false;
  135. }
  136. if ( 'page' === $post->post_type ) {
  137. return get_page_link( $post, $leavename, $sample );
  138. } elseif ( 'attachment' === $post->post_type ) {
  139. return get_attachment_link( $post, $leavename );
  140. } elseif ( in_array( $post->post_type, get_post_types( array( '_builtin' => false ) ), true ) ) {
  141. return get_post_permalink( $post, $leavename, $sample );
  142. }
  143. $permalink = get_option( 'permalink_structure' );
  144. /**
  145. * Filters the permalink structure for a post before token replacement occurs.
  146. *
  147. * Only applies to posts with post_type of 'post'.
  148. *
  149. * @since 3.0.0
  150. *
  151. * @param string $permalink The site's permalink structure.
  152. * @param WP_Post $post The post in question.
  153. * @param bool $leavename Whether to keep the post name.
  154. */
  155. $permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename );
  156. if ( '' != $permalink && ! in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft', 'future' ), true ) ) {
  157. $category = '';
  158. if ( strpos( $permalink, '%category%' ) !== false ) {
  159. $cats = get_the_category( $post->ID );
  160. if ( $cats ) {
  161. $cats = wp_list_sort(
  162. $cats,
  163. array(
  164. 'term_id' => 'ASC',
  165. )
  166. );
  167. /**
  168. * Filters the category that gets used in the %category% permalink token.
  169. *
  170. * @since 3.5.0
  171. *
  172. * @param WP_Term $cat The category to use in the permalink.
  173. * @param array $cats Array of all categories (WP_Term objects) associated with the post.
  174. * @param WP_Post $post The post in question.
  175. */
  176. $category_object = apply_filters( 'post_link_category', $cats[0], $cats, $post );
  177. $category_object = get_term( $category_object, 'category' );
  178. $category = $category_object->slug;
  179. if ( $category_object->parent ) {
  180. $category = get_category_parents( $category_object->parent, false, '/', true ) . $category;
  181. }
  182. }
  183. // Show default category in permalinks,
  184. // without having to assign it explicitly.
  185. if ( empty( $category ) ) {
  186. $default_category = get_term( get_option( 'default_category' ), 'category' );
  187. if ( $default_category && ! is_wp_error( $default_category ) ) {
  188. $category = $default_category->slug;
  189. }
  190. }
  191. }
  192. $author = '';
  193. if ( strpos( $permalink, '%author%' ) !== false ) {
  194. $authordata = get_userdata( $post->post_author );
  195. $author = $authordata->user_nicename;
  196. }
  197. // This is not an API call because the permalink is based on the stored post_date value,
  198. // which should be parsed as local time regardless of the default PHP timezone.
  199. $date = explode( ' ', str_replace( array( '-', ':' ), ' ', $post->post_date ) );
  200. $rewritereplace = array(
  201. $date[0],
  202. $date[1],
  203. $date[2],
  204. $date[3],
  205. $date[4],
  206. $date[5],
  207. $post->post_name,
  208. $post->ID,
  209. $category,
  210. $author,
  211. $post->post_name,
  212. );
  213. $permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) );
  214. $permalink = user_trailingslashit( $permalink, 'single' );
  215. } else { // If they're not using the fancy permalink option.
  216. $permalink = home_url( '?p=' . $post->ID );
  217. }
  218. /**
  219. * Filters the permalink for a post.
  220. *
  221. * Only applies to posts with post_type of 'post'.
  222. *
  223. * @since 1.5.0
  224. *
  225. * @param string $permalink The post's permalink.
  226. * @param WP_Post $post The post in question.
  227. * @param bool $leavename Whether to keep the post name.
  228. */
  229. return apply_filters( 'post_link', $permalink, $post, $leavename );
  230. }
  231. /**
  232. * Retrieves the permalink for a post of a custom post type.
  233. *
  234. * @since 3.0.0
  235. *
  236. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  237. *
  238. * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
  239. * @param bool $leavename Optional, defaults to false. Whether to keep post name. Default false.
  240. * @param bool $sample Optional, defaults to false. Is it a sample permalink. Default false.
  241. * @return string|WP_Error The post permalink.
  242. */
  243. function get_post_permalink( $id = 0, $leavename = false, $sample = false ) {
  244. global $wp_rewrite;
  245. $post = get_post( $id );
  246. if ( is_wp_error( $post ) ) {
  247. return $post;
  248. }
  249. $post_link = $wp_rewrite->get_extra_permastruct( $post->post_type );
  250. $slug = $post->post_name;
  251. $draft_or_pending = get_post_status( $post ) && in_array( get_post_status( $post ), array( 'draft', 'pending', 'auto-draft', 'future' ), true );
  252. $post_type = get_post_type_object( $post->post_type );
  253. if ( $post_type->hierarchical ) {
  254. $slug = get_page_uri( $post );
  255. }
  256. if ( ! empty( $post_link ) && ( ! $draft_or_pending || $sample ) ) {
  257. if ( ! $leavename ) {
  258. $post_link = str_replace( "%$post->post_type%", $slug, $post_link );
  259. }
  260. $post_link = home_url( user_trailingslashit( $post_link ) );
  261. } else {
  262. if ( $post_type->query_var && ( isset( $post->post_status ) && ! $draft_or_pending ) ) {
  263. $post_link = add_query_arg( $post_type->query_var, $slug, '' );
  264. } else {
  265. $post_link = add_query_arg(
  266. array(
  267. 'post_type' => $post->post_type,
  268. 'p' => $post->ID,
  269. ),
  270. ''
  271. );
  272. }
  273. $post_link = home_url( $post_link );
  274. }
  275. /**
  276. * Filters the permalink for a post of a custom post type.
  277. *
  278. * @since 3.0.0
  279. *
  280. * @param string $post_link The post's permalink.
  281. * @param WP_Post $post The post in question.
  282. * @param bool $leavename Whether to keep the post name.
  283. * @param bool $sample Is it a sample permalink.
  284. */
  285. return apply_filters( 'post_type_link', $post_link, $post, $leavename, $sample );
  286. }
  287. /**
  288. * Retrieves the permalink for the current page or page ID.
  289. *
  290. * Respects page_on_front. Use this one.
  291. *
  292. * @since 1.5.0
  293. *
  294. * @param int|WP_Post $post Optional. Post ID or object. Default uses the global `$post`.
  295. * @param bool $leavename Optional. Whether to keep the page name. Default false.
  296. * @param bool $sample Optional. Whether it should be treated as a sample permalink.
  297. * Default false.
  298. * @return string The page permalink.
  299. */
  300. function get_page_link( $post = false, $leavename = false, $sample = false ) {
  301. $post = get_post( $post );
  302. if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) == $post->ID ) {
  303. $link = home_url( '/' );
  304. } else {
  305. $link = _get_page_link( $post, $leavename, $sample );
  306. }
  307. /**
  308. * Filters the permalink for a page.
  309. *
  310. * @since 1.5.0
  311. *
  312. * @param string $link The page's permalink.
  313. * @param int $post_id The ID of the page.
  314. * @param bool $sample Is it a sample permalink.
  315. */
  316. return apply_filters( 'page_link', $link, $post->ID, $sample );
  317. }
  318. /**
  319. * Retrieves the page permalink.
  320. *
  321. * Ignores page_on_front. Internal use only.
  322. *
  323. * @since 2.1.0
  324. * @access private
  325. *
  326. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  327. *
  328. * @param int|WP_Post $post Optional. Post ID or object. Default uses the global `$post`.
  329. * @param bool $leavename Optional. Whether to keep the page name. Default false.
  330. * @param bool $sample Optional. Whether it should be treated as a sample permalink.
  331. * Default false.
  332. * @return string The page permalink.
  333. */
  334. function _get_page_link( $post = false, $leavename = false, $sample = false ) {
  335. global $wp_rewrite;
  336. $post = get_post( $post );
  337. $draft_or_pending = in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ), true );
  338. $link = $wp_rewrite->get_page_permastruct();
  339. if ( ! empty( $link ) && ( ( isset( $post->post_status ) && ! $draft_or_pending ) || $sample ) ) {
  340. if ( ! $leavename ) {
  341. $link = str_replace( '%pagename%', get_page_uri( $post ), $link );
  342. }
  343. $link = home_url( $link );
  344. $link = user_trailingslashit( $link, 'page' );
  345. } else {
  346. $link = home_url( '?page_id=' . $post->ID );
  347. }
  348. /**
  349. * Filters the permalink for a non-page_on_front page.
  350. *
  351. * @since 2.1.0
  352. *
  353. * @param string $link The page's permalink.
  354. * @param int $post_id The ID of the page.
  355. */
  356. return apply_filters( '_get_page_link', $link, $post->ID );
  357. }
  358. /**
  359. * Retrieves the permalink for an attachment.
  360. *
  361. * This can be used in the WordPress Loop or outside of it.
  362. *
  363. * @since 2.0.0
  364. *
  365. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  366. *
  367. * @param int|object $post Optional. Post ID or object. Default uses the global `$post`.
  368. * @param bool $leavename Optional. Whether to keep the page name. Default false.
  369. * @return string The attachment permalink.
  370. */
  371. function get_attachment_link( $post = null, $leavename = false ) {
  372. global $wp_rewrite;
  373. $link = false;
  374. $post = get_post( $post );
  375. $parent = ( $post->post_parent > 0 && $post->post_parent != $post->ID ) ? get_post( $post->post_parent ) : false;
  376. if ( $parent && ! in_array( $parent->post_type, get_post_types(), true ) ) {
  377. $parent = false;
  378. }
  379. if ( $wp_rewrite->using_permalinks() && $parent ) {
  380. if ( 'page' === $parent->post_type ) {
  381. $parentlink = _get_page_link( $post->post_parent ); // Ignores page_on_front.
  382. } else {
  383. $parentlink = get_permalink( $post->post_parent );
  384. }
  385. if ( is_numeric( $post->post_name ) || false !== strpos( get_option( 'permalink_structure' ), '%category%' ) ) {
  386. $name = 'attachment/' . $post->post_name; // <permalink>/<int>/ is paged so we use the explicit attachment marker.
  387. } else {
  388. $name = $post->post_name;
  389. }
  390. if ( strpos( $parentlink, '?' ) === false ) {
  391. $link = user_trailingslashit( trailingslashit( $parentlink ) . '%postname%' );
  392. }
  393. if ( ! $leavename ) {
  394. $link = str_replace( '%postname%', $name, $link );
  395. }
  396. } elseif ( $wp_rewrite->using_permalinks() && ! $leavename ) {
  397. $link = home_url( user_trailingslashit( $post->post_name ) );
  398. }
  399. if ( ! $link ) {
  400. $link = home_url( '/?attachment_id=' . $post->ID );
  401. }
  402. /**
  403. * Filters the permalink for an attachment.
  404. *
  405. * @since 2.0.0
  406. *
  407. * @param string $link The attachment's permalink.
  408. * @param int $post_id Attachment ID.
  409. */
  410. return apply_filters( 'attachment_link', $link, $post->ID );
  411. }
  412. /**
  413. * Retrieves the permalink for the year archives.
  414. *
  415. * @since 1.5.0
  416. *
  417. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  418. *
  419. * @param int|false $year Integer of year. False for current year.
  420. * @return string The permalink for the specified year archive.
  421. */
  422. function get_year_link( $year ) {
  423. global $wp_rewrite;
  424. if ( ! $year ) {
  425. $year = current_time( 'Y' );
  426. }
  427. $yearlink = $wp_rewrite->get_year_permastruct();
  428. if ( ! empty( $yearlink ) ) {
  429. $yearlink = str_replace( '%year%', $year, $yearlink );
  430. $yearlink = home_url( user_trailingslashit( $yearlink, 'year' ) );
  431. } else {
  432. $yearlink = home_url( '?m=' . $year );
  433. }
  434. /**
  435. * Filters the year archive permalink.
  436. *
  437. * @since 1.5.0
  438. *
  439. * @param string $yearlink Permalink for the year archive.
  440. * @param int $year Year for the archive.
  441. */
  442. return apply_filters( 'year_link', $yearlink, $year );
  443. }
  444. /**
  445. * Retrieves the permalink for the month archives with year.
  446. *
  447. * @since 1.0.0
  448. *
  449. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  450. *
  451. * @param int|false $year Integer of year. False for current year.
  452. * @param int|false $month Integer of month. False for current month.
  453. * @return string The permalink for the specified month and year archive.
  454. */
  455. function get_month_link( $year, $month ) {
  456. global $wp_rewrite;
  457. if ( ! $year ) {
  458. $year = current_time( 'Y' );
  459. }
  460. if ( ! $month ) {
  461. $month = current_time( 'm' );
  462. }
  463. $monthlink = $wp_rewrite->get_month_permastruct();
  464. if ( ! empty( $monthlink ) ) {
  465. $monthlink = str_replace( '%year%', $year, $monthlink );
  466. $monthlink = str_replace( '%monthnum%', zeroise( intval( $month ), 2 ), $monthlink );
  467. $monthlink = home_url( user_trailingslashit( $monthlink, 'month' ) );
  468. } else {
  469. $monthlink = home_url( '?m=' . $year . zeroise( $month, 2 ) );
  470. }
  471. /**
  472. * Filters the month archive permalink.
  473. *
  474. * @since 1.5.0
  475. *
  476. * @param string $monthlink Permalink for the month archive.
  477. * @param int $year Year for the archive.
  478. * @param int $month The month for the archive.
  479. */
  480. return apply_filters( 'month_link', $monthlink, $year, $month );
  481. }
  482. /**
  483. * Retrieves the permalink for the day archives with year and month.
  484. *
  485. * @since 1.0.0
  486. *
  487. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  488. *
  489. * @param int|false $year Integer of year. False for current year.
  490. * @param int|false $month Integer of month. False for current month.
  491. * @param int|false $day Integer of day. False for current day.
  492. * @return string The permalink for the specified day, month, and year archive.
  493. */
  494. function get_day_link( $year, $month, $day ) {
  495. global $wp_rewrite;
  496. if ( ! $year ) {
  497. $year = current_time( 'Y' );
  498. }
  499. if ( ! $month ) {
  500. $month = current_time( 'm' );
  501. }
  502. if ( ! $day ) {
  503. $day = current_time( 'j' );
  504. }
  505. $daylink = $wp_rewrite->get_day_permastruct();
  506. if ( ! empty( $daylink ) ) {
  507. $daylink = str_replace( '%year%', $year, $daylink );
  508. $daylink = str_replace( '%monthnum%', zeroise( intval( $month ), 2 ), $daylink );
  509. $daylink = str_replace( '%day%', zeroise( intval( $day ), 2 ), $daylink );
  510. $daylink = home_url( user_trailingslashit( $daylink, 'day' ) );
  511. } else {
  512. $daylink = home_url( '?m=' . $year . zeroise( $month, 2 ) . zeroise( $day, 2 ) );
  513. }
  514. /**
  515. * Filters the day archive permalink.
  516. *
  517. * @since 1.5.0
  518. *
  519. * @param string $daylink Permalink for the day archive.
  520. * @param int $year Year for the archive.
  521. * @param int $month Month for the archive.
  522. * @param int $day The day for the archive.
  523. */
  524. return apply_filters( 'day_link', $daylink, $year, $month, $day );
  525. }
  526. /**
  527. * Displays the permalink for the feed type.
  528. *
  529. * @since 3.0.0
  530. *
  531. * @param string $anchor The link's anchor text.
  532. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  533. * Default is the value of get_default_feed().
  534. */
  535. function the_feed_link( $anchor, $feed = '' ) {
  536. $link = '<a href="' . esc_url( get_feed_link( $feed ) ) . '">' . $anchor . '</a>';
  537. /**
  538. * Filters the feed link anchor tag.
  539. *
  540. * @since 3.0.0
  541. *
  542. * @param string $link The complete anchor tag for a feed link.
  543. * @param string $feed The feed type. Possible values include 'rss2', 'atom',
  544. * or an empty string for the default feed type.
  545. */
  546. echo apply_filters( 'the_feed_link', $link, $feed );
  547. }
  548. /**
  549. * Retrieves the permalink for the feed type.
  550. *
  551. * @since 1.5.0
  552. *
  553. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  554. *
  555. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  556. * Default is the value of get_default_feed().
  557. * @return string The feed permalink.
  558. */
  559. function get_feed_link( $feed = '' ) {
  560. global $wp_rewrite;
  561. $permalink = $wp_rewrite->get_feed_permastruct();
  562. if ( '' != $permalink ) {
  563. if ( false !== strpos( $feed, 'comments_' ) ) {
  564. $feed = str_replace( 'comments_', '', $feed );
  565. $permalink = $wp_rewrite->get_comment_feed_permastruct();
  566. }
  567. if ( get_default_feed() == $feed ) {
  568. $feed = '';
  569. }
  570. $permalink = str_replace( '%feed%', $feed, $permalink );
  571. $permalink = preg_replace( '#/+#', '/', "/$permalink" );
  572. $output = home_url( user_trailingslashit( $permalink, 'feed' ) );
  573. } else {
  574. if ( empty( $feed ) ) {
  575. $feed = get_default_feed();
  576. }
  577. if ( false !== strpos( $feed, 'comments_' ) ) {
  578. $feed = str_replace( 'comments_', 'comments-', $feed );
  579. }
  580. $output = home_url( "?feed={$feed}" );
  581. }
  582. /**
  583. * Filters the feed type permalink.
  584. *
  585. * @since 1.5.0
  586. *
  587. * @param string $output The feed permalink.
  588. * @param string $feed The feed type. Possible values include 'rss2', 'atom',
  589. * or an empty string for the default feed type.
  590. */
  591. return apply_filters( 'feed_link', $output, $feed );
  592. }
  593. /**
  594. * Retrieves the permalink for the post comments feed.
  595. *
  596. * @since 2.2.0
  597. *
  598. * @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
  599. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  600. * Default is the value of get_default_feed().
  601. * @return string The permalink for the comments feed for the given post.
  602. */
  603. function get_post_comments_feed_link( $post_id = 0, $feed = '' ) {
  604. $post_id = absint( $post_id );
  605. if ( ! $post_id ) {
  606. $post_id = get_the_ID();
  607. }
  608. if ( empty( $feed ) ) {
  609. $feed = get_default_feed();
  610. }
  611. $post = get_post( $post_id );
  612. $unattached = 'attachment' === $post->post_type && 0 === (int) $post->post_parent;
  613. if ( '' != get_option( 'permalink_structure' ) ) {
  614. if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) == $post_id ) {
  615. $url = _get_page_link( $post_id );
  616. } else {
  617. $url = get_permalink( $post_id );
  618. }
  619. if ( $unattached ) {
  620. $url = home_url( '/feed/' );
  621. if ( get_default_feed() !== $feed ) {
  622. $url .= "$feed/";
  623. }
  624. $url = add_query_arg( 'attachment_id', $post_id, $url );
  625. } else {
  626. $url = trailingslashit( $url ) . 'feed';
  627. if ( get_default_feed() != $feed ) {
  628. $url .= "/$feed";
  629. }
  630. $url = user_trailingslashit( $url, 'single_feed' );
  631. }
  632. } else {
  633. if ( $unattached ) {
  634. $url = add_query_arg(
  635. array(
  636. 'feed' => $feed,
  637. 'attachment_id' => $post_id,
  638. ),
  639. home_url( '/' )
  640. );
  641. } elseif ( 'page' === $post->post_type ) {
  642. $url = add_query_arg(
  643. array(
  644. 'feed' => $feed,
  645. 'page_id' => $post_id,
  646. ),
  647. home_url( '/' )
  648. );
  649. } else {
  650. $url = add_query_arg(
  651. array(
  652. 'feed' => $feed,
  653. 'p' => $post_id,
  654. ),
  655. home_url( '/' )
  656. );
  657. }
  658. }
  659. /**
  660. * Filters the post comments feed permalink.
  661. *
  662. * @since 1.5.1
  663. *
  664. * @param string $url Post comments feed permalink.
  665. */
  666. return apply_filters( 'post_comments_feed_link', $url );
  667. }
  668. /**
  669. * Displays the comment feed link for a post.
  670. *
  671. * Prints out the comment feed link for a post. Link text is placed in the
  672. * anchor. If no link text is specified, default text is used. If no post ID is
  673. * specified, the current post is used.
  674. *
  675. * @since 2.5.0
  676. *
  677. * @param string $link_text Optional. Descriptive link text. Default 'Comments Feed'.
  678. * @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
  679. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  680. * Default is the value of get_default_feed().
  681. */
  682. function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
  683. $url = get_post_comments_feed_link( $post_id, $feed );
  684. if ( empty( $link_text ) ) {
  685. $link_text = __( 'Comments Feed' );
  686. }
  687. $link = '<a href="' . esc_url( $url ) . '">' . $link_text . '</a>';
  688. /**
  689. * Filters the post comment feed link anchor tag.
  690. *
  691. * @since 2.8.0
  692. *
  693. * @param string $link The complete anchor tag for the comment feed link.
  694. * @param int $post_id Post ID.
  695. * @param string $feed The feed type. Possible values include 'rss2', 'atom',
  696. * or an empty string for the default feed type.
  697. */
  698. echo apply_filters( 'post_comments_feed_link_html', $link, $post_id, $feed );
  699. }
  700. /**
  701. * Retrieves the feed link for a given author.
  702. *
  703. * Returns a link to the feed for all posts by a given author. A specific feed
  704. * can be requested or left blank to get the default feed.
  705. *
  706. * @since 2.5.0
  707. *
  708. * @param int $author_id Author ID.
  709. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  710. * Default is the value of get_default_feed().
  711. * @return string Link to the feed for the author specified by $author_id.
  712. */
  713. function get_author_feed_link( $author_id, $feed = '' ) {
  714. $author_id = (int) $author_id;
  715. $permalink_structure = get_option( 'permalink_structure' );
  716. if ( empty( $feed ) ) {
  717. $feed = get_default_feed();
  718. }
  719. if ( '' == $permalink_structure ) {
  720. $link = home_url( "?feed=$feed&amp;author=" . $author_id );
  721. } else {
  722. $link = get_author_posts_url( $author_id );
  723. if ( get_default_feed() == $feed ) {
  724. $feed_link = 'feed';
  725. } else {
  726. $feed_link = "feed/$feed";
  727. }
  728. $link = trailingslashit( $link ) . user_trailingslashit( $feed_link, 'feed' );
  729. }
  730. /**
  731. * Filters the feed link for a given author.
  732. *
  733. * @since 1.5.1
  734. *
  735. * @param string $link The author feed link.
  736. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  737. */
  738. $link = apply_filters( 'author_feed_link', $link, $feed );
  739. return $link;
  740. }
  741. /**
  742. * Retrieves the feed link for a category.
  743. *
  744. * Returns a link to the feed for all posts in a given category. A specific feed
  745. * can be requested or left blank to get the default feed.
  746. *
  747. * @since 2.5.0
  748. *
  749. * @param int $cat_id Category ID.
  750. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  751. * Default is the value of get_default_feed().
  752. * @return string Link to the feed for the category specified by $cat_id.
  753. */
  754. function get_category_feed_link( $cat_id, $feed = '' ) {
  755. return get_term_feed_link( $cat_id, 'category', $feed );
  756. }
  757. /**
  758. * Retrieves the feed link for a term.
  759. *
  760. * Returns a link to the feed for all posts in a given term. A specific feed
  761. * can be requested or left blank to get the default feed.
  762. *
  763. * @since 3.0.0
  764. *
  765. * @param int $term_id Term ID.
  766. * @param string $taxonomy Optional. Taxonomy of `$term_id`. Default 'category'.
  767. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  768. * Default is the value of get_default_feed().
  769. * @return string|false Link to the feed for the term specified by $term_id and $taxonomy.
  770. */
  771. function get_term_feed_link( $term_id, $taxonomy = 'category', $feed = '' ) {
  772. $term_id = (int) $term_id;
  773. $term = get_term( $term_id, $taxonomy );
  774. if ( empty( $term ) || is_wp_error( $term ) ) {
  775. return false;
  776. }
  777. if ( empty( $feed ) ) {
  778. $feed = get_default_feed();
  779. }
  780. $permalink_structure = get_option( 'permalink_structure' );
  781. if ( '' == $permalink_structure ) {
  782. if ( 'category' == $taxonomy ) {
  783. $link = home_url( "?feed=$feed&amp;cat=$term_id" );
  784. } elseif ( 'post_tag' == $taxonomy ) {
  785. $link = home_url( "?feed=$feed&amp;tag=$term->slug" );
  786. } else {
  787. $t = get_taxonomy( $taxonomy );
  788. $link = home_url( "?feed=$feed&amp;$t->query_var=$term->slug" );
  789. }
  790. } else {
  791. $link = get_term_link( $term_id, $term->taxonomy );
  792. if ( get_default_feed() == $feed ) {
  793. $feed_link = 'feed';
  794. } else {
  795. $feed_link = "feed/$feed";
  796. }
  797. $link = trailingslashit( $link ) . user_trailingslashit( $feed_link, 'feed' );
  798. }
  799. if ( 'category' == $taxonomy ) {
  800. /**
  801. * Filters the category feed link.
  802. *
  803. * @since 1.5.1
  804. *
  805. * @param string $link The category feed link.
  806. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  807. */
  808. $link = apply_filters( 'category_feed_link', $link, $feed );
  809. } elseif ( 'post_tag' == $taxonomy ) {
  810. /**
  811. * Filters the post tag feed link.
  812. *
  813. * @since 2.3.0
  814. *
  815. * @param string $link The tag feed link.
  816. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  817. */
  818. $link = apply_filters( 'tag_feed_link', $link, $feed );
  819. } else {
  820. /**
  821. * Filters the feed link for a taxonomy other than 'category' or 'post_tag'.
  822. *
  823. * @since 3.0.0
  824. *
  825. * @param string $link The taxonomy feed link.
  826. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  827. * @param string $taxonomy The taxonomy name.
  828. */
  829. $link = apply_filters( 'taxonomy_feed_link', $link, $feed, $taxonomy );
  830. }
  831. return $link;
  832. }
  833. /**
  834. * Retrieves the permalink for a tag feed.
  835. *
  836. * @since 2.3.0
  837. *
  838. * @param int $tag_id Tag ID.
  839. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  840. * Default is the value of get_default_feed().
  841. * @return string The feed permalink for the given tag.
  842. */
  843. function get_tag_feed_link( $tag_id, $feed = '' ) {
  844. return get_term_feed_link( $tag_id, 'post_tag', $feed );
  845. }
  846. /**
  847. * Retrieves the edit link for a tag.
  848. *
  849. * @since 2.7.0
  850. *
  851. * @param int $tag_id Tag ID.
  852. * @param string $taxonomy Optional. Taxonomy slug. Default 'post_tag'.
  853. * @return string The edit tag link URL for the given tag.
  854. */
  855. function get_edit_tag_link( $tag_id, $taxonomy = 'post_tag' ) {
  856. /**
  857. * Filters the edit link for a tag (or term in another taxonomy).
  858. *
  859. * @since 2.7.0
  860. *
  861. * @param string $link The term edit link.
  862. */
  863. return apply_filters( 'get_edit_tag_link', get_edit_term_link( $tag_id, $taxonomy ) );
  864. }
  865. /**
  866. * Displays or retrieves the edit link for a tag with formatting.
  867. *
  868. * @since 2.7.0
  869. *
  870. * @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
  871. * @param string $before Optional. Display before edit link. Default empty.
  872. * @param string $after Optional. Display after edit link. Default empty.
  873. * @param WP_Term $tag Optional. Term object. If null, the queried object will be inspected.
  874. * Default null.
  875. */
  876. function edit_tag_link( $link = '', $before = '', $after = '', $tag = null ) {
  877. $link = edit_term_link( $link, '', '', $tag, false );
  878. /**
  879. * Filters the anchor tag for the edit link for a tag (or term in another taxonomy).
  880. *
  881. * @since 2.7.0
  882. *
  883. * @param string $link The anchor tag for the edit link.
  884. */
  885. echo $before . apply_filters( 'edit_tag_link', $link ) . $after;
  886. }
  887. /**
  888. * Retrieves the URL for editing a given term.
  889. *
  890. * @since 3.1.0
  891. * @since 4.5.0 The `$taxonomy` parameter was made optional.
  892. *
  893. * @param int $term_id Term ID.
  894. * @param string $taxonomy Optional. Taxonomy. Defaults to the taxonomy of the term identified
  895. * by `$term_id`.
  896. * @param string $object_type Optional. The object type. Used to highlight the proper post type
  897. * menu on the linked page. Defaults to the first object_type associated
  898. * with the taxonomy.
  899. * @return string|null The edit term link URL for the given term, or null on failure.
  900. */
  901. function get_edit_term_link( $term_id, $taxonomy = '', $object_type = '' ) {
  902. $term = get_term( $term_id, $taxonomy );
  903. if ( ! $term || is_wp_error( $term ) ) {
  904. return;
  905. }
  906. $tax = get_taxonomy( $term->taxonomy );
  907. if ( ! $tax || ! current_user_can( 'edit_term', $term->term_id ) ) {
  908. return;
  909. }
  910. $args = array(
  911. 'taxonomy' => $taxonomy,
  912. 'tag_ID' => $term->term_id,
  913. );
  914. if ( $object_type ) {
  915. $args['post_type'] = $object_type;
  916. } elseif ( ! empty( $tax->object_type ) ) {
  917. $args['post_type'] = reset( $tax->object_type );
  918. }
  919. if ( $tax->show_ui ) {
  920. $location = add_query_arg( $args, admin_url( 'term.php' ) );
  921. } else {
  922. $location = '';
  923. }
  924. /**
  925. * Filters the edit link for a term.
  926. *
  927. * @since 3.1.0
  928. *
  929. * @param string $location The edit link.
  930. * @param int $term_id Term ID.
  931. * @param string $taxonomy Taxonomy name.
  932. * @param string $object_type The object type (eg. the post type).
  933. */
  934. return apply_filters( 'get_edit_term_link', $location, $term_id, $taxonomy, $object_type );
  935. }
  936. /**
  937. * Displays or retrieves the edit term link with formatting.
  938. *
  939. * @since 3.1.0
  940. *
  941. * @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
  942. * @param string $before Optional. Display before edit link. Default empty.
  943. * @param string $after Optional. Display after edit link. Default empty.
  944. * @param WP_Term $term Optional. Term object. If null, the queried object will be inspected. Default null.
  945. * @param bool $echo Optional. Whether or not to echo the return. Default true.
  946. * @return string|void HTML content.
  947. */
  948. function edit_term_link( $link = '', $before = '', $after = '', $term = null, $echo = true ) {
  949. if ( is_null( $term ) ) {
  950. $term = get_queried_object();
  951. }
  952. if ( ! $term ) {
  953. return;
  954. }
  955. $tax = get_taxonomy( $term->taxonomy );
  956. if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
  957. return;
  958. }
  959. if ( empty( $link ) ) {
  960. $link = __( 'Edit This' );
  961. }
  962. $link = '<a href="' . get_edit_term_link( $term->term_id, $term->taxonomy ) . '">' . $link . '</a>';
  963. /**
  964. * Filters the anchor tag for the edit link of a term.
  965. *
  966. * @since 3.1.0
  967. *
  968. * @param string $link The anchor tag for the edit link.
  969. * @param int $term_id Term ID.
  970. */
  971. $link = $before . apply_filters( 'edit_term_link', $link, $term->term_id ) . $after;
  972. if ( $echo ) {
  973. echo $link;
  974. } else {
  975. return $link;
  976. }
  977. }
  978. /**
  979. * Retrieves the permalink for a search.
  980. *
  981. * @since 3.0.0
  982. *
  983. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  984. *
  985. * @param string $query Optional. The query string to use. If empty the current query is used. Default empty.
  986. * @return string The search permalink.
  987. */
  988. function get_search_link( $query = '' ) {
  989. global $wp_rewrite;
  990. if ( empty( $query ) ) {
  991. $search = get_search_query( false );
  992. } else {
  993. $search = stripslashes( $query );
  994. }
  995. $permastruct = $wp_rewrite->get_search_permastruct();
  996. if ( empty( $permastruct ) ) {
  997. $link = home_url( '?s=' . urlencode( $search ) );
  998. } else {
  999. $search = urlencode( $search );
  1000. $search = str_replace( '%2F', '/', $search ); // %2F(/) is not valid within a URL, send it un-encoded.
  1001. $link = str_replace( '%search%', $search, $permastruct );
  1002. $link = home_url( user_trailingslashit( $link, 'search' ) );
  1003. }
  1004. /**
  1005. * Filters the search permalink.
  1006. *
  1007. * @since 3.0.0
  1008. *
  1009. * @param string $link Search permalink.
  1010. * @param string $search The URL-encoded search term.
  1011. */
  1012. return apply_filters( 'search_link', $link, $search );
  1013. }
  1014. /**
  1015. * Retrieves the permalink for the search results feed.
  1016. *
  1017. * @since 2.5.0
  1018. *
  1019. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  1020. *
  1021. * @param string $search_query Optional. Search query. Default empty.
  1022. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  1023. * Default is the value of get_default_feed().
  1024. * @return string The search results feed permalink.
  1025. */
  1026. function get_search_feed_link( $search_query = '', $feed = '' ) {
  1027. global $wp_rewrite;
  1028. $link = get_search_link( $search_query );
  1029. if ( empty( $feed ) ) {
  1030. $feed = get_default_feed();
  1031. }
  1032. $permastruct = $wp_rewrite->get_search_permastruct();
  1033. if ( empty( $permastruct ) ) {
  1034. $link = add_query_arg( 'feed', $feed, $link );
  1035. } else {
  1036. $link = trailingslashit( $link );
  1037. $link .= "feed/$feed/";
  1038. }
  1039. /**
  1040. * Filters the search feed link.
  1041. *
  1042. * @since 2.5.0
  1043. *
  1044. * @param string $link Search feed link.
  1045. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  1046. * @param string $type The search type. One of 'posts' or 'comments'.
  1047. */
  1048. return apply_filters( 'search_feed_link', $link, $feed, 'posts' );
  1049. }
  1050. /**
  1051. * Retrieves the permalink for the search results comments feed.
  1052. *
  1053. * @since 2.5.0
  1054. *
  1055. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  1056. *
  1057. * @param string $search_query Optional. Search query. Default empty.
  1058. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  1059. * Default is the value of get_default_feed().
  1060. * @return string The comments feed search results permalink.
  1061. */
  1062. function get_search_comments_feed_link( $search_query = '', $feed = '' ) {
  1063. global $wp_rewrite;
  1064. if ( empty( $feed ) ) {
  1065. $feed = get_default_feed();
  1066. }
  1067. $link = get_search_feed_link( $search_query, $feed );
  1068. $permastruct = $wp_rewrite->get_search_permastruct();
  1069. if ( empty( $permastruct ) ) {
  1070. $link = add_query_arg( 'feed', 'comments-' . $feed, $link );
  1071. } else {
  1072. $link = add_query_arg( 'withcomments', 1, $link );
  1073. }
  1074. /** This filter is documented in wp-includes/link-template.php */
  1075. return apply_filters( 'search_feed_link', $link, $feed, 'comments' );
  1076. }
  1077. /**
  1078. * Retrieves the permalink for a post type archive.
  1079. *
  1080. * @since 3.1.0
  1081. * @since 4.5.0 Support for posts was added.
  1082. *
  1083. * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  1084. *
  1085. * @param string $post_type Post type.
  1086. * @return string|false The post type archive permalink.
  1087. */
  1088. function get_post_type_archive_link( $post_type ) {
  1089. global $wp_rewrite;
  1090. $post_type_obj = get_post_type_object( $post_type );
  1091. if ( ! $post_type_obj ) {
  1092. return false;
  1093. }
  1094. if ( 'post' === $post_type ) {
  1095. $show_on_front = get_option( 'show_on_front' );
  1096. $page_for_posts = get_option( 'page_for_posts' );
  1097. if ( 'page' === $show_on_front && $page_for_posts ) {
  1098. $link = get_permalink( $page_for_posts );
  1099. } else {
  1100. $link = get_home_url();
  1101. }
  1102. /** This filter is documented in wp-includes/link-template.php */
  1103. return apply_filters( 'post_type_archive_link', $link, $post_type );
  1104. }
  1105. if ( ! $post_type_obj->has_archive ) {
  1106. return false;
  1107. }
  1108. if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) ) {
  1109. $struct = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive;
  1110. if ( $post_type_obj->rewrite['with_front'] ) {
  1111. $struct = $wp_rewrite->front . $struct;
  1112. } else {
  1113. $struct = $wp_rewrite->root . $struct;
  1114. }
  1115. $link = home_url( user_trailingslashit( $struct, 'post_type_archive' ) );
  1116. } else {
  1117. $link = home_url( '?post_type=' . $post_type );
  1118. }
  1119. /**
  1120. * Filters the post type archive permalink.
  1121. *
  1122. * @since 3.1.0
  1123. *
  1124. * @param string $link The post type archive permalink.
  1125. * @param string $post_type Post type name.
  1126. */
  1127. return apply_filters( 'post_type_archive_link', $link, $post_type );
  1128. }
  1129. /**
  1130. * Retrieves the permalink for a post type archive feed.
  1131. *
  1132. * @since 3.1.0
  1133. *
  1134. * @param string $post_type Post type
  1135. * @param string $feed Optional. Feed type. Possible values include 'rss2', 'atom'.
  1136. * Default is the value of get_default_feed().
  1137. * @return string|false The post type feed permalink.
  1138. */
  1139. function get_post_type_archive_feed_link( $post_type, $feed = '' ) {
  1140. $default_feed = get_default_feed();
  1141. if ( empty( $feed ) ) {
  1142. $feed = $default_feed;
  1143. }
  1144. $link = get_post_type_archive_link( $post_type );
  1145. if ( ! $link ) {
  1146. return false;
  1147. }
  1148. $post_type_obj = get_post_type_object( $post_type );
  1149. if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) && $post_type_obj->rewrite['feeds'] ) {
  1150. $link = trailingslashit( $link );
  1151. $link .= 'feed/';
  1152. if ( $feed != $default_feed ) {
  1153. $link .= "$feed/";
  1154. }
  1155. } else {
  1156. $link = add_query_arg( 'feed', $feed, $link );
  1157. }
  1158. /**
  1159. * Filters the post type archive feed link.
  1160. *
  1161. * @since 3.1.0
  1162. *
  1163. * @param string $link The post type archive feed link.
  1164. * @param string $feed Feed type. Possible values include 'rss2', 'atom'.
  1165. */
  1166. return apply_filters( 'post_type_archive_feed_link', $link, $feed );
  1167. }
  1168. /**
  1169. * Retrieves the URL used for the post preview.
  1170. *
  1171. * Allows additional query args to be appended.
  1172. *
  1173. * @since 4.4.0
  1174. *
  1175. * @param int|WP_Post $post Optional. Post ID or `WP_Post` object. Defaults to global `$post`.
  1176. * @param array $query_args Optional. Array of additional query args to be appended to the link.
  1177. * Default empty array.
  1178. * @param string $preview_link Optional. Base preview link to be used if it should differ from the
  1179. * post permalink. Default empty.
  1180. * @return string|null URL used for the post preview, or null if the post does not exist.
  1181. */
  1182. function get_preview_post_link( $post = null, $query_args = array(), $preview_link = '' ) {
  1183. $post = get_post( $post );
  1184. if ( ! $post ) {
  1185. return;
  1186. }
  1187. $post_type_object = get_post_type_object( $post->post_type );
  1188. if ( is_post_type_viewable( $post_type_object ) ) {
  1189. if ( ! $preview_link ) {
  1190. $preview_link = set_url_scheme( get_permalink( $post ) );
  1191. }
  1192. $query_args['preview'] = 'true';
  1193. $preview_link = add_query_arg( $query_args, $preview_link );
  1194. }
  1195. /**
  1196. * Filters the URL used for a post preview.
  1197. *
  1198. * @since 2.0.5
  1199. * @since 4.0.0 Added the `$post` parameter.
  1200. *
  1201. * @param string $preview_link URL used for the post preview.
  1202. * @param WP_Post $post Post object.
  1203. */
  1204. return apply_filters( 'preview_post_link', $preview_link, $post );
  1205. }
  1206. /**
  1207. * Retrieves the edit post link for post.
  1208. *
  1209. * Can be used within the WordPress loop or outside of it. Can be used with
  1210. * pages, posts, attachments, and revisions.
  1211. *
  1212. * @since 2.3.0
  1213. *
  1214. * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
  1215. * @param string $context Optional. How to output the '&' character. Default '&amp;'.
  1216. * @return string|null The edit post link for the given post. null if the post type is invalid or does
  1217. * not allow an editing UI.
  1218. */
  1219. function get_edit_post_link( $id = 0, $context = 'display' ) {
  1220. $post = get_post( $id );
  1221. if ( ! $post ) {
  1222. return;
  1223. }
  1224. if ( 'revision' === $post->post_type ) {
  1225. $action = '';
  1226. } elseif ( 'display' == $context ) {
  1227. $action = '&amp;action=edit';
  1228. } else {
  1229. $action = '&action=edit';
  1230. }
  1231. $post_type_object = get_post_type_object( $post->post_type );
  1232. if ( ! $post_type_object ) {
  1233. return;
  1234. }
  1235. if ( ! current_user_can( 'edit_post', $post->ID ) ) {
  1236. return;
  1237. }
  1238. if ( $post_type_object->_edit_link ) {
  1239. $link = admin_url( sprintf( $post_type_object->_edit_link . $action, $post->ID ) );
  1240. } else {
  1241. $link = '';
  1242. }
  1243. /**
  1244. * Filters the post edit link.
  1245. *
  1246. * @since 2.3.0
  1247. *
  1248. * @param string $link The edit link.
  1249. * @param int $post_id Post ID.
  1250. * @param string $context The link context. If set to 'display' then ampersands
  1251. * are encoded.
  1252. */
  1253. return apply_filters( 'get_edit_post_link', $link, $post->ID, $context );
  1254. }
  1255. /**
  1256. * Displays the edit post link for post.
  1257. *
  1258. * @since 1.0.0
  1259. * @since 4.4.0 The `$class` argument was added.
  1260. *
  1261. * @param string $text Optional. Anchor text. If null, default is 'Edit This'. Default null.
  1262. * @param string $before Optional. Display before edit link. Default empty.
  1263. * @param string $after Optional. Display after edit link. Default empty.
  1264. * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
  1265. * @param string $class Optional. Add custom class to link. Default 'post-edit-link'.
  1266. */
  1267. function edit_post_link( $text = null, $before = '', $after = '', $id = 0, $class = 'post-edit-link' ) {
  1268. $post = get_post( $id );
  1269. if ( ! $post ) {
  1270. return;
  1271. }
  1272. $url = get_edit_post_link( $post->ID );
  1273. if ( ! $url ) {
  1274. return;
  1275. }
  1276. if ( null === $text ) {
  1277. $text = __( 'Edit This' );
  1278. }
  1279. $link = '<a class="' . esc_attr( $class ) . '" href="' . esc_url( $url ) . '">' . $text . '</a>';
  1280. /**
  1281. * Filters the post edit link anchor tag.
  1282. *
  1283. * @since 2.3.0
  1284. *
  1285. * @param string $link Anchor tag for the edit link.
  1286. * @param int $post_id Post ID.
  1287. * @param string $text Anchor text.
  1288. */
  1289. echo $before . apply_filters( 'edit_post_link', $link, $post->ID, $text ) . $after;
  1290. }
  1291. /**
  1292. * Retrieves the delete posts link for post.
  1293. *
  1294. * Can be used within the WordPress loop or outside of it, with any post type.
  1295. *
  1296. * @since 2.9.0
  1297. *
  1298. * @param int|WP_Post $id Optional. Post ID or post object. Default is the global `$post`.
  1299. * @param string $deprecated Not used.
  1300. * @param bool $force_delete Optional. Whether to bypass Trash and force deletion. Default false.
  1301. * @return string|void The delete post link URL for the given post.
  1302. */
  1303. function get_delete_post_link( $id = 0, $deprecated = '', $force_delete = false ) {
  1304. if ( ! empty( $deprecated ) ) {
  1305. _deprecated_argument( __FUNCTION__, '3.0.0' );
  1306. }
  1307. $post = get_post( $id );
  1308. if ( ! $post ) {
  1309. return;
  1310. }
  1311. $post_type_object = get_post_type_object( $post->post_type );
  1312. if ( ! $post_type_object ) {
  1313. return;
  1314. }
  1315. if ( ! current_user_can( 'delete_post', $post->ID ) ) {
  1316. return;
  1317. }
  1318. $action = ( $force_delete || ! EMPTY_TRASH_DAYS ) ? 'delete' : 'trash';
  1319. $delete_link = add_query_arg( 'action', $action, admin_url( sprintf( $post_type_object->_edit_link, $post->ID ) ) );
  1320. /**
  1321. * Filters the post delete link.
  1322. *
  1323. * @since 2.9.0
  1324. *
  1325. * @param string $link The delete link.
  1326. * @param int $post_id Post ID.
  1327. * @param bool $force_delete Whether to bypass the Trash and force deletion. Default false.
  1328. */
  1329. return apply_filters( 'get_delete_post_link', wp_nonce_url( $delete_link, "$action-post_{$post->ID}" ), $post->ID, $force_delete );
  1330. }
  1331. /**
  1332. * Retrieves the edit comment link.
  1333. *
  1334. * @since 2.3.0
  1335. *
  1336. * @param int|WP_Comment $comment_id Optional. Comment ID or WP_Comment object.
  1337. * @return string|void The edit comment link URL for the given comment.
  1338. */
  1339. function get_edit_comment_link( $comment_id = 0 ) {
  1340. $comment = get_comment( $comment_id );
  1341. if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) {
  1342. return;
  1343. }
  1344. $location = admin_url( 'comment.php?action=editcomment&amp;c=' ) . $comment->comment_ID;
  1345. /**
  1346. * Filters the comment edit link.
  1347. *
  1348. * @since 2.3.0
  1349. *
  1350. * @param string $location The edit link.
  1351. */
  1352. return apply_filters( 'get_edit_comment_link', $location );
  1353. }
  1354. /**
  1355. * Displays the edit comment link with formatting.
  1356. *
  1357. * @since 1.0.0
  1358. *
  1359. * @param string $text Optional. Anchor text. If null, default is 'Edit This'. Default null.
  1360. * @param string $before Optional. Display before edit link. Default empty.
  1361. * @param string $after Optional. Display after edit link. Default empty.
  1362. */
  1363. function edit_comment_link( $text = null, $before = '', $after = '' ) {
  1364. $comment = get_comment();
  1365. if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) {
  1366. return;
  1367. }
  1368. if ( null === $text ) {
  1369. $text = __( 'Edit This' );
  1370. }
  1371. $link = '<a class="comment-edit-link" href="' . esc_url( get_edit_comment_link( $comment ) ) . '">' . $text . '</a>';
  1372. /**
  1373. * Filters the comment edit link anchor tag.
  1374. *
  1375. * @since 2.3.0
  1376. *
  1377. * @param string $link Anchor tag for the edit link.
  1378. * @param int $comment_id Comment ID.
  1379. * @param string $text Anchor text.
  1380. */
  1381. echo $before . apply_filters( 'edit_comment_link', $link, $comment->comment_ID, $text ) . $after;
  1382. }
  1383. /**
  1384. * Displays the edit bookmark link.
  1385. *
  1386. * @since 2.7.0
  1387. *
  1388. * @param int|stdClass $link Optional. Bookmark ID. Default is the id of the current bookmark.
  1389. * @return string|void The edit bookmark link URL.
  1390. */
  1391. function get_edit_bookmark_link( $link = 0 ) {
  1392. $link = get_bookmark( $link );
  1393. if ( ! current_user_can( 'manage_links' ) ) {
  1394. return;
  1395. }
  1396. $location = admin_url( 'link.php?action=edit&amp;link_id=' ) . $link->link_id;
  1397. /**
  1398. * Filters the bookmark edit link.
  1399. *
  1400. * @since 2.7.0
  1401. *
  1402. * @param string $location The edit link.
  1403. * @param int $link_id Bookmark ID.
  1404. */
  1405. return apply_filters( 'get_edit_bookmark_link', $location, $link->link_id );
  1406. }
  1407. /**
  1408. * Displays the edit bookmark link anchor content.
  1409. *
  1410. * @since 2.7.0
  1411. *
  1412. * @param string $link Optional. Anchor text. If empty, default is 'Edit This'. Default empty.
  1413. * @param string $before Optional. Display before edit link. Default empty.
  1414. * @param string $after Optional. Display after edit link. Default empty.
  1415. * @param int $bookmark Optional. Bookmark ID. Default is the current bookmark.
  1416. */
  1417. function edit_bookmark_link( $link = '', $before = '', $after = '', $bookmark = null ) {
  1418. $bookmark = get_bookmark( $bookmark );
  1419. if ( ! current_user_can( 'manage_links' ) ) {
  1420. return;
  1421. }
  1422. if ( empty( $link ) ) {
  1423. $link = __( 'Edit This' );
  1424. }
  1425. $link = '<a href="' . esc_url( get_edit_bookmark_link( $bookmark ) ) . '">' . $link . '</a>';
  1426. /**
  1427. * Filters the bookmark edit link anchor tag.
  1428. *
  1429. * @since 2.7.0
  1430. *
  1431. * @param string $link Anchor tag for the edit link.
  1432. * @param int $link_id Bookmark ID.
  1433. */
  1434. echo $before . apply_filters( 'edit_bookmark_link', $link, $bookmark->link_id ) . $after;
  1435. }
  1436. /**
  1437. * Retrieves the edit user link.
  1438. *
  1439. * @since 3.5.0
  1440. *
  1441. * @param int $user_id Optional. User ID. Defaults to the current user.
  1442. * @return string URL to edit user page or empty string.
  1443. */
  1444. function get_edit_user_link( $user_id = null ) {
  1445. if ( ! $user_id ) {
  1446. $user_id = get_current_user_id();
  1447. }
  1448. if ( empty( $user_id ) || ! current_user_can( 'edit_user', $user_id ) ) {
  1449. return '';
  1450. }
  1451. $user = get_userdata( $user_id );
  1452. if ( ! $user ) {
  1453. return '';
  1454. }
  1455. if ( get_current_user_id() == $user->ID ) {
  1456. $link = get_edit_profile_url( $user->ID );
  1457. } else {
  1458. $link = add_query_arg( 'user_id', $user->ID, self_admin_url( 'user-edit.php' ) );
  1459. }
  1460. /**
  1461. * Filters the user edit link.
  1462. *
  1463. * @since 3.5.0
  1464. *
  1465. * @param string $link The edit link.
  1466. * @param int $user_id User ID.
  1467. */
  1468. return apply_filters( 'get_edit_user_link', $link, $user->ID );
  1469. }
  1470. //
  1471. // Navigation links.
  1472. //
  1473. /**
  1474. * Retrieves the previous post that is adjacent to the current post.
  1475. *
  1476. * @since 1.5.0
  1477. *
  1478. * @param bool $in_same_term Optional. Whether post should be in a same taxonomy term. Default false.
  1479. * @param array|string $excluded_terms Optional. Array or comma-separated list of excluded term IDs. Default empty.
  1480. * @param string $taxonomy Optional. Taxonomy, if $in_same_term is true. Default 'category'.
  1481. * @return null|string|WP_Post Post object if successful. Null if global $post is not set. Empty string if no
  1482. * corresponding post exists.
  1483. */
  1484. function get_previous_post( $in_same_term = false, $excluded_terms = '', $taxonomy = 'category' ) {
  1485. return get_adjacent_post( $in_same_term, $excluded_terms, true, $taxonomy );
  1486. }
  1487. /**
  1488. * Retrieves the next post that is adjacent to the current post.
  1489. *
  1490. * @since 1.5.0
  1491. *
  1492. * @param bool $in_same_term Optional. Whether post should be in …

Large files files are truncated, but you can click here to view the full file