PageRenderTime 37ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/post.php

https://github.com/localshred/dtraders
PHP | 3445 lines | 1618 code | 461 blank | 1366 comment | 465 complexity | de5cedc51a7936a8f6f0db6b11c88bf8 MD5 | raw file
  1. <?php
  2. /**
  3. * Post functions and post utility function.
  4. *
  5. * Warning: The inline documentation for the functions contained
  6. * in this file might be inaccurate, so the documentation is not
  7. * authoritative at the moment.
  8. *
  9. * @package WordPress
  10. * @subpackage Post
  11. * @since 1.5
  12. */
  13. /**
  14. * Retrieve attached file path based on attachment ID.
  15. *
  16. * You can optionally send it through the 'get_attached_file' filter, but by
  17. * default it will just return the file path unfiltered.
  18. *
  19. * The function works by getting the single post meta name, named
  20. * '_wp_attached_file' and returning it. This is a convenience function to
  21. * prevent looking up the meta name and provide a mechanism for sending the
  22. * attached filename through a filter.
  23. *
  24. * @package WordPress
  25. * @subpackage Post
  26. * @since 2.0
  27. * @uses apply_filters() Calls 'get_attached_file' on file path and attachment ID
  28. *
  29. * @param int $attachment_id Attachment ID
  30. * @param bool $unfiltered Whether to apply filters or not
  31. * @return string The file path to the attached file.
  32. */
  33. function get_attached_file( $attachment_id, $unfiltered = false ) {
  34. $file = get_post_meta( $attachment_id, '_wp_attached_file', true );
  35. if ( $unfiltered )
  36. return $file;
  37. return apply_filters( 'get_attached_file', $file, $attachment_id );
  38. }
  39. /**
  40. * Update attachment file path based on attachment ID.
  41. *
  42. * Used to update the file path of the attachment, which uses post meta name
  43. * '_wp_attached_file' to store the path of the attachment.
  44. *
  45. * @package WordPress
  46. * @subpackage Post
  47. * @since 2.1
  48. * @uses apply_filters() Calls 'update_attached_file' on file path and attachment ID
  49. *
  50. * @param int $attachment_id Attachment ID
  51. * @param string $file File path for the attachment
  52. * @return bool False on failure, true on success.
  53. */
  54. function update_attached_file( $attachment_id, $file ) {
  55. if ( !get_post( $attachment_id ) )
  56. return false;
  57. $file = apply_filters( 'update_attached_file', $file, $attachment_id );
  58. return update_post_meta( $attachment_id, '_wp_attached_file', $file );
  59. }
  60. /**
  61. * Retrieve all children of the post parent ID.
  62. *
  63. * Normally, without any enhancements, the children would apply to pages. In the
  64. * context of the inner workings of WordPress, pages, posts, and attachments
  65. * share the same table, so therefore the functionality could apply to any one
  66. * of them. It is then noted that while this function does not work on posts, it
  67. * does not mean that it won't work on posts. It is recommended that you know
  68. * what context you wish to retrieve the children of.
  69. *
  70. * Attachments may also be made the child of a post, so if that is an accurate
  71. * statement (which needs to be verified), it would then be possible to get
  72. * all of the attachments for a post. Attachments have since changed since
  73. * version 2.5, so this is most likely unaccurate, but serves generally as an
  74. * example of what is possible.
  75. *
  76. * The arguments listed as defaults are for this function and also of the
  77. * get_posts() function. The arguments are combined with the get_children
  78. * defaults and are then passed to the get_posts() function, which accepts
  79. * additional arguments. You can replace the defaults in this function, listed
  80. * below and the additional arguments listed in the get_posts() function.
  81. *
  82. * The 'post_parent' is the most important argument and important attention
  83. * needs to be paid to the $args parameter. If you pass either an object or an
  84. * integer (number), then just the 'post_parent' is grabbed and everything else
  85. * is lost. If you don't specify any arguments, then it is assumed that you are
  86. * in The Loop and the post parent will be grabbed for from the current post.
  87. *
  88. * The 'post_parent' argument is the ID to get the children. The 'numberposts'
  89. * is the amount of posts to retrieve that has a default of '-1', which is
  90. * used to get all of the posts. Giving a number higher than 0 will only
  91. * retrieve that amount of posts.
  92. *
  93. * The 'post_type' and 'post_status' arguments can be used to choose what
  94. * criteria of posts to retrieve. The 'post_type' can be anything, but WordPress
  95. * post types are 'post', 'pages', and 'attachments'. The 'post_status'
  96. * argument will accept any post status within the write administration panels.
  97. *
  98. * @see get_posts() Has additional arguments that can be replaced.
  99. * @internal Claims made in the long description might be inaccurate.
  100. *
  101. * @package WordPress
  102. * @subpackage Post
  103. * @since 2.0
  104. *
  105. * @param mixed $args Optional. User defined arguments for replacing the defaults.
  106. * @param string $output Optional. Constant for return type, either OBJECT (default), ARRAY_A, ARRAY_N.
  107. * @return array|bool False on failure and the type will be determined by $output parameter.
  108. */
  109. function &get_children($args = '', $output = OBJECT) {
  110. if ( empty( $args ) ) {
  111. if ( isset( $GLOBALS['post'] ) ) {
  112. $args = array('post_parent' => (int) $GLOBALS['post']->post_parent );
  113. } else {
  114. return false;
  115. }
  116. } elseif ( is_object( $args ) ) {
  117. $args = array('post_parent' => (int) $args->post_parent );
  118. } elseif ( is_numeric( $args ) ) {
  119. $args = array('post_parent' => (int) $args);
  120. }
  121. $defaults = array(
  122. 'numberposts' => -1, 'post_type' => '',
  123. 'post_status' => '', 'post_parent' => 0
  124. );
  125. $r = wp_parse_args( $args, $defaults );
  126. $children = get_posts( $r );
  127. if ( !$children )
  128. return false;
  129. update_post_cache($children);
  130. foreach ( $children as $key => $child )
  131. $kids[$child->ID] =& $children[$key];
  132. if ( $output == OBJECT ) {
  133. return $kids;
  134. } elseif ( $output == ARRAY_A ) {
  135. foreach ( $kids as $kid )
  136. $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
  137. return $weeuns;
  138. } elseif ( $output == ARRAY_N ) {
  139. foreach ( $kids as $kid )
  140. $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
  141. return $babes;
  142. } else {
  143. return $kids;
  144. }
  145. }
  146. /**
  147. * get_extended() - Get extended entry info (<!--more-->)
  148. *
  149. * {@internal Missing Long Description}}
  150. *
  151. * @package WordPress
  152. * @subpackage Post
  153. * @since 1.0.0
  154. *
  155. * @param string $post {@internal Missing Description}}
  156. * @return array {@internal Missing Description}}
  157. */
  158. function get_extended($post) {
  159. //Match the new style more links
  160. if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
  161. list($main, $extended) = explode($matches[0], $post, 2);
  162. } else {
  163. $main = $post;
  164. $extended = '';
  165. }
  166. // Strip leading and trailing whitespace
  167. $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
  168. $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
  169. return array('main' => $main, 'extended' => $extended);
  170. }
  171. /**
  172. * get_post() - Retrieves post data given a post ID or post object.
  173. *
  174. * {@internal Missing Long Description}}
  175. *
  176. * @package WordPress
  177. * @subpackage Post
  178. * @since 1.5.1
  179. * @uses $wpdb
  180. * @link http://codex.wordpress.org/Function_Reference/get_post
  181. *
  182. * @param int|object &$post post ID or post object
  183. * @param string $output {@internal Missing Description}}
  184. * @param string $filter {@internal Missing Description}}
  185. * @return mixed {@internal Missing Description}}
  186. */
  187. function &get_post(&$post, $output = OBJECT, $filter = 'raw') {
  188. global $wpdb;
  189. $null = null;
  190. if ( empty($post) ) {
  191. if ( isset($GLOBALS['post']) )
  192. $_post = & $GLOBALS['post'];
  193. else
  194. return $null;
  195. } elseif ( is_object($post) ) {
  196. _get_post_ancestors($post);
  197. wp_cache_add($post->ID, $post, 'posts');
  198. $_post = &$post;
  199. } else {
  200. $post = (int) $post;
  201. if ( ! $_post = wp_cache_get($post, 'posts') ) {
  202. $_post = & $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post));
  203. if ( ! $_post )
  204. return $null;
  205. _get_post_ancestors($_post);
  206. wp_cache_add($_post->ID, $_post, 'posts');
  207. }
  208. }
  209. $_post = sanitize_post($_post, $filter);
  210. if ( $output == OBJECT ) {
  211. return $_post;
  212. } elseif ( $output == ARRAY_A ) {
  213. $__post = get_object_vars($_post);
  214. return $__post;
  215. } elseif ( $output == ARRAY_N ) {
  216. $__post = array_values(get_object_vars($_post));
  217. return $__post;
  218. } else {
  219. return $_post;
  220. }
  221. }
  222. /**
  223. * Retrieve ancestors of a post.
  224. *
  225. * @package WordPress
  226. * @subpackage Post
  227. * @since 2.5
  228. *
  229. * @param int|object $post Post ID or post object
  230. * @return array Ancestor IDs or empty array if none are found.
  231. */
  232. function get_post_ancestors($post) {
  233. $post = get_post($post);
  234. if ( !empty($post->ancestors) )
  235. return $post->ancestors;
  236. return array();
  237. }
  238. /**
  239. * Retrieve data from a post field based on Post ID.
  240. *
  241. * Examples of the post field will be, 'post_type', 'post_status', 'content',
  242. * etc and based off of the post object property or key names.
  243. *
  244. * The context values are based off of the taxonomy filter functions and
  245. * supported values are found within those functions.
  246. *
  247. * @package WordPress
  248. * @subpackage Post
  249. * @since 2.3
  250. * @uses sanitize_post_field() See for possible $context values.
  251. *
  252. * @param string $field Post field name
  253. * @param id $post Post ID
  254. * @param string $context Optional. How to filter the field. Default is display.
  255. * @return WP_Error|string Value in post field or WP_Error on failure
  256. */
  257. function get_post_field( $field, $post, $context = 'display' ) {
  258. $post = (int) $post;
  259. $post = get_post( $post );
  260. if ( is_wp_error($post) )
  261. return $post;
  262. if ( !is_object($post) )
  263. return '';
  264. if ( !isset($post->$field) )
  265. return '';
  266. return sanitize_post_field($field, $post->$field, $post->ID, $context);
  267. }
  268. /**
  269. * Retrieve the mime type of an attachment based on the ID.
  270. *
  271. * This function can be used with any post type, but it makes more sense with
  272. * attachments.
  273. *
  274. * @package WordPress
  275. * @subpackage Post
  276. * @since 2.0
  277. *
  278. * @param int $ID Optional. Post ID.
  279. * @return bool|string False on failure or returns the mime type
  280. */
  281. function get_post_mime_type($ID = '') {
  282. $post = & get_post($ID);
  283. if ( is_object($post) )
  284. return $post->post_mime_type;
  285. return false;
  286. }
  287. /**
  288. * Retrieve the post status based on the Post ID.
  289. *
  290. * If the post ID is of an attachment, then the parent post status will be given
  291. * instead.
  292. *
  293. * @package WordPress
  294. * @subpackage Post
  295. * @since 2.0
  296. *
  297. * @param int $ID Post ID
  298. * @return string|bool Post status or false on failure.
  299. */
  300. function get_post_status($ID = '') {
  301. $post = get_post($ID);
  302. if ( is_object($post) ) {
  303. if ( ('attachment' == $post->post_type) && $post->post_parent && ($post->ID != $post->post_parent) )
  304. return get_post_status($post->post_parent);
  305. else
  306. return $post->post_status;
  307. }
  308. return false;
  309. }
  310. /**
  311. * Retrieve all of the WordPress supported post statuses.
  312. *
  313. * Posts have a limited set of valid status values, this provides the
  314. * post_status values and descriptions.
  315. *
  316. * @package WordPress
  317. * @subpackage Post
  318. * @since 2.5
  319. *
  320. * @return array List of post statuses.
  321. */
  322. function get_post_statuses( ) {
  323. $status = array(
  324. 'draft' => __('Draft'),
  325. 'pending' => __('Pending Review'),
  326. 'private' => __('Private'),
  327. 'publish' => __('Published')
  328. );
  329. return $status;
  330. }
  331. /**
  332. * Retrieve all of the WordPress support page statuses.
  333. *
  334. * Pages have a limited set of valid status values, this provides the
  335. * post_status values and descriptions.
  336. *
  337. * @package WordPress
  338. * @subpackage Page
  339. * @since 2.5
  340. *
  341. * @return array List of page statuses.
  342. */
  343. function get_page_statuses( ) {
  344. $status = array(
  345. 'draft' => __('Draft'),
  346. 'private' => __('Private'),
  347. 'publish' => __('Published')
  348. );
  349. return $status;
  350. }
  351. /**
  352. * get_post_type() - Returns post type
  353. *
  354. * {@internal Missing Long Description}}
  355. *
  356. * @package WordPress
  357. * @subpackage Post
  358. * @since 2.1
  359. *
  360. * @uses $wpdb
  361. * @uses $posts {@internal Missing Description}}
  362. *
  363. * @param mixed $post post object or post ID
  364. * @return mixed post type or false
  365. */
  366. function get_post_type($post = false) {
  367. global $posts;
  368. if ( false === $post )
  369. $post = $posts[0];
  370. elseif ( (int) $post )
  371. $post = get_post($post, OBJECT);
  372. if ( is_object($post) )
  373. return $post->post_type;
  374. return false;
  375. }
  376. /**
  377. * set_post_type() - Set post type
  378. *
  379. * {@internal Missing Long Description}}
  380. *
  381. * @package WordPress
  382. * @subpackage Post
  383. * @since 2.5
  384. *
  385. * @uses $wpdb
  386. * @uses $posts {@internal Missing Description}}
  387. *
  388. * @param mixed $post_id post ID
  389. * @param mixed post type
  390. * @return bool {@internal Missing Description}}
  391. */
  392. function set_post_type( $post_id = 0, $post_type = 'post' ) {
  393. global $wpdb;
  394. $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
  395. $return = $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_type = %s WHERE ID = %d", $post_type, $post_id) );
  396. if ( 'page' == $post_type )
  397. clean_page_cache($post_id);
  398. else
  399. clean_post_cache($post_id);
  400. return $return;
  401. }
  402. /**
  403. * get_posts() - Returns a number of posts
  404. *
  405. * {@internal Missing Long Description}}
  406. *
  407. * @package WordPress
  408. * @subpackage Post
  409. * @since 1.2
  410. * @uses $wpdb
  411. * @link http://codex.wordpress.org/Template_Tags/get_posts
  412. *
  413. * @param array $args {@internal Missing Description}}
  414. * @return array {@internal Missing Description}}
  415. */
  416. function get_posts($args = null) {
  417. $defaults = array(
  418. 'numberposts' => 5, 'offset' => 0,
  419. 'category' => 0, 'orderby' => 'post_date',
  420. 'order' => 'DESC', 'include' => '',
  421. 'exclude' => '', 'meta_key' => '',
  422. 'meta_value' =>'', 'post_type' => 'post',
  423. 'post_parent' => 0
  424. );
  425. $r = wp_parse_args( $args, $defaults );
  426. if ( empty( $r['post_status'] ) )
  427. $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
  428. if ( ! empty($r['numberposts']) )
  429. $r['posts_per_page'] = $r['numberposts'];
  430. if ( ! empty($r['category']) )
  431. $r['cat'] = $r['category'];
  432. if ( ! empty($r['include']) ) {
  433. $incposts = preg_split('/[\s,]+/',$r['include']);
  434. $r['posts_per_page'] = count($incposts); // only the number of posts included
  435. $r['post__in'] = $incposts;
  436. } elseif ( ! empty($r['exclude']) )
  437. $r['post__not_in'] = preg_split('/[\s,]+/',$r['exclude']);
  438. $get_posts = new WP_Query;
  439. return $get_posts->query($r);
  440. }
  441. //
  442. // Post meta functions
  443. //
  444. /**
  445. * add_post_meta() - adds metadata for post
  446. *
  447. * {@internal Missing Long Description}}
  448. *
  449. * @package WordPress
  450. * @subpackage Post
  451. * @since 1.5
  452. * @uses $wpdb
  453. * @link http://codex.wordpress.org/Function_Reference/add_post_meta
  454. *
  455. * @param int $post_id post ID
  456. * @param string $key {@internal Missing Description}}
  457. * @param mixed $value {@internal Missing Description}}
  458. * @param bool $unique whether to check for a value with the same key
  459. * @return bool {@internal Missing Description}}
  460. */
  461. function add_post_meta($post_id, $meta_key, $meta_value, $unique = false) {
  462. global $wpdb;
  463. // make sure meta is added to the post, not a revision
  464. if ( $the_post = wp_is_post_revision($post_id) )
  465. $post_id = $the_post;
  466. // expected_slashed ($meta_key)
  467. $meta_key = stripslashes($meta_key);
  468. if ( $unique && $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) )
  469. return false;
  470. $meta_value = maybe_serialize($meta_value);
  471. $wpdb->insert( $wpdb->postmeta, compact( 'post_id', 'meta_key', 'meta_value' ) );
  472. wp_cache_delete($post_id, 'post_meta');
  473. return true;
  474. }
  475. /**
  476. * delete_post_meta() - delete post metadata
  477. *
  478. * {@internal Missing Long Description}}
  479. *
  480. * @package WordPress
  481. * @subpackage Post
  482. * @since 1.5
  483. * @uses $wpdb
  484. * @link http://codex.wordpress.org/Function_Reference/delete_post_meta
  485. *
  486. * @param int $post_id post ID
  487. * @param string $key {@internal Missing Description}}
  488. * @param mixed $value {@internal Missing Description}}
  489. * @return bool {@internal Missing Description}}
  490. */
  491. function delete_post_meta($post_id, $key, $value = '') {
  492. global $wpdb;
  493. $post_id = absint( $post_id );
  494. // expected_slashed ($key, $value)
  495. $key = stripslashes( $key );
  496. $value = stripslashes( $value );
  497. if ( empty( $value ) )
  498. $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $key ) );
  499. else
  500. $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $key, $value ) );
  501. if ( !$meta_id )
  502. return false;
  503. if ( empty( $value ) )
  504. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s", $post_id, $key ) );
  505. else
  506. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $key, $value ) );
  507. wp_cache_delete($post_id, 'post_meta');
  508. return true;
  509. }
  510. /**
  511. * get_post_meta() - Get a post meta field
  512. *
  513. * {@internal Missing Long Description}}
  514. *
  515. * @package WordPress
  516. * @subpackage Post
  517. * @since 1.5
  518. * @uses $wpdb
  519. * @link http://codex.wordpress.org/Function_Reference/get_post_meta
  520. *
  521. * @param int $post_id post ID
  522. * @param string $key The meta key to retrieve
  523. * @param bool $single Whether to return a single value
  524. * @return mixed {@internal Missing Description}}
  525. */
  526. function get_post_meta($post_id, $key, $single = false) {
  527. $post_id = (int) $post_id;
  528. $meta_cache = wp_cache_get($post_id, 'post_meta');
  529. if ( isset($meta_cache[$key]) ) {
  530. if ( $single ) {
  531. return maybe_unserialize( $meta_cache[$key][0] );
  532. } else {
  533. return maybe_unserialize( $meta_cache[$key] );
  534. }
  535. }
  536. if ( !$meta_cache ) {
  537. update_postmeta_cache($post_id);
  538. $meta_cache = wp_cache_get($post_id, 'post_meta');
  539. }
  540. if ( $single ) {
  541. if ( isset($meta_cache[$key][0]) )
  542. return maybe_unserialize($meta_cache[$key][0]);
  543. else
  544. return '';
  545. } else {
  546. return maybe_unserialize($meta_cache[$key]);
  547. }
  548. }
  549. /**
  550. * update_post_meta() - Update a post meta field
  551. *
  552. * {@internal Missing Long Description}}
  553. *
  554. * @package WordPress
  555. * @subpackage Post
  556. * @since 1.5
  557. * @uses $wpdb
  558. * @link http://codex.wordpress.org/Function_Reference/update_post_meta
  559. *
  560. * @param int $post_id post ID
  561. * @param string $key {@internal Missing Description}}
  562. * @param mixed $value {@internal Missing Description}}
  563. * @param mixed $prev_value previous value (for differentiating between meta fields with the same key and post ID)
  564. * @return bool {@internal Missing Description}}
  565. */
  566. function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') {
  567. global $wpdb;
  568. // expected_slashed ($meta_key)
  569. $meta_key = stripslashes($meta_key);
  570. if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d", $meta_key, $post_id ) ) ) {
  571. return add_post_meta($post_id, $meta_key, $meta_value);
  572. }
  573. $meta_value = maybe_serialize($meta_value);
  574. $data = compact( 'meta_value' );
  575. $where = compact( 'meta_key', 'post_id' );
  576. if ( !empty( $prev_value ) ) {
  577. $prev_value = maybe_serialize($prev_value);
  578. $where['meta_value'] = $prev_value;
  579. }
  580. $wpdb->update( $wpdb->postmeta, $data, $where );
  581. wp_cache_delete($post_id, 'post_meta');
  582. return true;
  583. }
  584. /**
  585. * delete_post_meta_by_key() - Delete everything from post meta matching $post_meta_key
  586. *
  587. * @package WordPress
  588. * @subpackage Post
  589. * @since 2.3
  590. * @uses $wpdb
  591. *
  592. * @param string $post_meta_key What to search for when deleting
  593. * @return bool Whether the post meta key was deleted from the database
  594. */
  595. function delete_post_meta_by_key($post_meta_key) {
  596. global $wpdb;
  597. if ( $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_key = %s", $post_meta_key)) ) {
  598. /** @todo Get post_ids and delete cache */
  599. // wp_cache_delete($post_id, 'post_meta');
  600. return true;
  601. }
  602. return false;
  603. }
  604. /**
  605. * get_post_custom() - Retrieve post custom fields
  606. *
  607. * {@internal Missing Long Description}}
  608. *
  609. * @package WordPress
  610. * @subpackage Post
  611. * @since 1.2
  612. * @link http://codex.wordpress.org/Function_Reference/get_post_custom
  613. *
  614. * @uses $id
  615. * @uses $wpdb
  616. *
  617. * @param int $post_id post ID
  618. * @return array {@internal Missing Description}}
  619. */
  620. function get_post_custom($post_id = 0) {
  621. global $id;
  622. if ( !$post_id )
  623. $post_id = (int) $id;
  624. $post_id = (int) $post_id;
  625. if ( ! wp_cache_get($post_id, 'post_meta') )
  626. update_postmeta_cache($post_id);
  627. return wp_cache_get($post_id, 'post_meta');
  628. }
  629. /**
  630. * get_post_custom_keys() - Retrieve post custom field names
  631. *
  632. * @package WordPress
  633. * @subpackage Post
  634. * @since 1.2
  635. * @link http://codex.wordpress.org/Function_Reference/get_post_custom_keys
  636. *
  637. * @param int $post_id post ID
  638. * @return array|null Either array of the keys, or null if keys would not be retrieved
  639. */
  640. function get_post_custom_keys( $post_id = 0 ) {
  641. $custom = get_post_custom( $post_id );
  642. if ( !is_array($custom) )
  643. return;
  644. if ( $keys = array_keys($custom) )
  645. return $keys;
  646. }
  647. /**
  648. * get_post_custom_values() - Retrieve values for a custom post field
  649. *
  650. * @package WordPress
  651. * @subpackage Post
  652. * @since 1.2
  653. * @link http://codex.wordpress.org/Function_Reference/get_post_custom_values
  654. *
  655. * @param string $key field name
  656. * @param int $post_id post ID
  657. * @return mixed {@internal Missing Description}}
  658. */
  659. function get_post_custom_values( $key = '', $post_id = 0 ) {
  660. $custom = get_post_custom($post_id);
  661. return $custom[$key];
  662. }
  663. /**
  664. * sanitize_post() - Sanitize every post field
  665. *
  666. * {@internal Missing Long Description}}
  667. *
  668. * @package WordPress
  669. * @subpackage Post
  670. * @since 2.3
  671. *
  672. * @param object|array $post The Post Object or Array
  673. * @param string $context How to sanitize post fields
  674. * @return object|array The now sanitized Post Object or Array (will be the same type as $post)
  675. */
  676. function sanitize_post($post, $context = 'display') {
  677. if ( 'raw' == $context )
  678. return $post;
  679. if ( is_object($post) ) {
  680. foreach ( array_keys(get_object_vars($post)) as $field )
  681. $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
  682. } else {
  683. foreach ( array_keys($post) as $field )
  684. $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
  685. }
  686. return $post;
  687. }
  688. /**
  689. * sanitize_post_field() - Sanitize post field based on context
  690. *
  691. * {@internal Missing Long Description}}
  692. *
  693. * @package WordPress
  694. * @subpackage Post
  695. * @since 2.3
  696. *
  697. * @param string $field The Post Object field name
  698. * @param string $value The Post Object value
  699. * @param int $postid Post ID
  700. * @param string $context How to sanitize post fields
  701. * @return string Sanitized value
  702. */
  703. function sanitize_post_field($field, $value, $post_id, $context) {
  704. $int_fields = array('ID', 'post_parent', 'menu_order');
  705. if ( in_array($field, $int_fields) )
  706. $value = (int) $value;
  707. if ( 'raw' == $context )
  708. return $value;
  709. $prefixed = false;
  710. if ( false !== strpos($field, 'post_') ) {
  711. $prefixed = true;
  712. $field_no_prefix = str_replace('post_', '', $field);
  713. }
  714. if ( 'edit' == $context ) {
  715. $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
  716. if ( $prefixed ) {
  717. $value = apply_filters("edit_$field", $value, $post_id);
  718. // Old school
  719. $value = apply_filters("${field_no_prefix}_edit_pre", $value, $post_id);
  720. } else {
  721. $value = apply_filters("edit_post_$field", $value, $post_id);
  722. }
  723. if ( in_array($field, $format_to_edit) ) {
  724. if ( 'post_content' == $field )
  725. $value = format_to_edit($value, user_can_richedit());
  726. else
  727. $value = format_to_edit($value);
  728. } else {
  729. $value = attribute_escape($value);
  730. }
  731. } else if ( 'db' == $context ) {
  732. if ( $prefixed ) {
  733. $value = apply_filters("pre_$field", $value);
  734. $value = apply_filters("${field_no_prefix}_save_pre", $value);
  735. } else {
  736. $value = apply_filters("pre_post_$field", $value);
  737. $value = apply_filters("${field}_pre", $value);
  738. }
  739. } else {
  740. // Use display filters by default.
  741. if ( $prefixed )
  742. $value = apply_filters($field, $value, $post_id, $context);
  743. else
  744. $value = apply_filters("post_$field", $value, $post_id, $context);
  745. }
  746. if ( 'attribute' == $context )
  747. $value = attribute_escape($value);
  748. else if ( 'js' == $context )
  749. $value = js_escape($value);
  750. return $value;
  751. }
  752. /**
  753. * Count number of posts of a post type and is user has permissions to view.
  754. *
  755. * This function provides an efficient method of finding the amount of post's
  756. * type a blog has. Another method is to count the amount of items in
  757. * get_posts(), but that method has a lot of overhead with doing so. Therefore,
  758. * when developing for 2.5+, use this function instead.
  759. *
  760. * The $perm parameter checks for 'readable' value and if the user can read
  761. * private posts, it will display that for the user that is signed in.
  762. *
  763. * @package WordPress
  764. * @subpackage Post
  765. * @since 2.5
  766. * @link http://codex.wordpress.org/Template_Tags/wp_count_posts
  767. *
  768. * @param string $type Optional. Post type to retrieve count
  769. * @param string $perm Optional. 'readable' or empty.
  770. * @return object Number of posts for each status
  771. */
  772. function wp_count_posts( $type = 'post', $perm = '' ) {
  773. global $wpdb;
  774. $user = wp_get_current_user();
  775. $cache_key = $type;
  776. $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
  777. if ( 'readable' == $perm && is_user_logged_in() ) {
  778. if ( !current_user_can("read_private_{$type}s") ) {
  779. $cache_key .= '_' . $perm . '_' . $user->ID;
  780. $query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
  781. }
  782. }
  783. $query .= ' GROUP BY post_status';
  784. $count = wp_cache_get($cache_key, 'counts');
  785. if ( false !== $count )
  786. return $count;
  787. $count = $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
  788. $stats = array( );
  789. foreach( (array) $count as $row_num => $row ) {
  790. $stats[$row['post_status']] = $row['num_posts'];
  791. }
  792. $stats = (object) $stats;
  793. wp_cache_set($cache_key, $stats, 'counts');
  794. return $stats;
  795. }
  796. /**
  797. * wp_count_attachments() - Count number of attachments
  798. *
  799. * {@internal Missing Long Description}}
  800. *
  801. * @package WordPress
  802. * @subpackage Post
  803. * @since 2.5
  804. *
  805. * @param string|array $post_mime_type Array or comma-separated list of MIME patterns
  806. * @return array Number of posts for each post_mime_type
  807. */
  808. function wp_count_attachments( $mime_type = '' ) {
  809. global $wpdb;
  810. $and = wp_post_mime_type_where( $mime_type );
  811. $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' $and GROUP BY post_mime_type", ARRAY_A );
  812. $stats = array( );
  813. foreach( (array) $count as $row ) {
  814. $stats[$row['post_mime_type']] = $row['num_posts'];
  815. }
  816. return (object) $stats;
  817. }
  818. /**
  819. * wp_match_mime_type() - Check a MIME-Type against a list
  820. *
  821. * {@internal Missing Long Description}}
  822. *
  823. * @package WordPress
  824. * @subpackage Post
  825. * @since 2.5
  826. *
  827. * @param string|array $wildcard_mime_types e.g. audio/mpeg or image (same as image/*) or flash (same as *flash*)
  828. * @param string|array $real_mime_types post_mime_type values
  829. * @return array array(wildcard=>array(real types))
  830. */
  831. function wp_match_mime_types($wildcard_mime_types, $real_mime_types) {
  832. $matches = array();
  833. if ( is_string($wildcard_mime_types) )
  834. $wildcard_mime_types = array_map('trim', explode(',', $wildcard_mime_types));
  835. if ( is_string($real_mime_types) )
  836. $real_mime_types = array_map('trim', explode(',', $real_mime_types));
  837. $wild = '[-._a-z0-9]*';
  838. foreach ( (array) $wildcard_mime_types as $type ) {
  839. $type = str_replace('*', $wild, $type);
  840. $patternses[1][$type] = "^$type$";
  841. if ( false === strpos($type, '/') ) {
  842. $patternses[2][$type] = "^$type/";
  843. $patternses[3][$type] = $type;
  844. }
  845. }
  846. asort($patternses);
  847. foreach ( $patternses as $patterns )
  848. foreach ( $patterns as $type => $pattern )
  849. foreach ( (array) $real_mime_types as $real )
  850. if ( preg_match("#$pattern#", $real) && ( empty($matches[$type]) || false === array_search($real, $matches[$type]) ) )
  851. $matches[$type][] = $real;
  852. return $matches;
  853. }
  854. /**
  855. * wp_get_post_mime_type_where() - Convert MIME types into SQL
  856. *
  857. * @package WordPress
  858. * @subpackage Post
  859. * @since 2.5
  860. *
  861. * @param string|array $mime_types MIME types
  862. * @return string SQL AND clause
  863. */
  864. function wp_post_mime_type_where($post_mime_types) {
  865. $where = '';
  866. $wildcards = array('', '%', '%/%');
  867. if ( is_string($post_mime_types) )
  868. $post_mime_types = array_map('trim', explode(',', $post_mime_types));
  869. foreach ( (array) $post_mime_types as $mime_type ) {
  870. $mime_type = preg_replace('/\s/', '', $mime_type);
  871. $slashpos = strpos($mime_type, '/');
  872. if ( false !== $slashpos ) {
  873. $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
  874. $mime_subgroup = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
  875. if ( empty($mime_subgroup) )
  876. $mime_subgroup = '*';
  877. else
  878. $mime_subgroup = str_replace('/', '', $mime_subgroup);
  879. $mime_pattern = "$mime_group/$mime_subgroup";
  880. } else {
  881. $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
  882. if ( false === strpos($mime_pattern, '*') )
  883. $mime_pattern .= '/*';
  884. }
  885. $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
  886. if ( in_array( $mime_type, $wildcards ) )
  887. return '';
  888. if ( false !== strpos($mime_pattern, '%') )
  889. $wheres[] = "post_mime_type LIKE '$mime_pattern'";
  890. else
  891. $wheres[] = "post_mime_type = '$mime_pattern'";
  892. }
  893. if ( !empty($wheres) )
  894. $where = ' AND (' . join(' OR ', $wheres) . ') ';
  895. return $where;
  896. }
  897. /**
  898. * wp_delete_post() - Deletes a Post
  899. *
  900. * {@internal Missing Long Description}}
  901. *
  902. * @package WordPress
  903. * @subpackage Post
  904. * @since 1.0.0
  905. *
  906. * @param int $postid post ID
  907. * @return mixed {@internal Missing Description}}
  908. */
  909. function wp_delete_post($postid = 0) {
  910. global $wpdb, $wp_rewrite;
  911. if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
  912. return $post;
  913. if ( 'attachment' == $post->post_type )
  914. return wp_delete_attachment($postid);
  915. do_action('delete_post', $postid);
  916. /** @todo delete for pluggable post taxonomies too */
  917. wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
  918. $parent_data = array( 'post_parent' => $post->post_parent );
  919. $parent_where = array( 'post_parent' => $postid );
  920. if ( 'page' == $post->post_type) {
  921. // if the page is defined in option page_on_front or post_for_posts,
  922. // adjust the corresponding options
  923. if ( get_option('page_on_front') == $postid ) {
  924. update_option('show_on_front', 'posts');
  925. delete_option('page_on_front');
  926. }
  927. if ( get_option('page_for_posts') == $postid ) {
  928. delete_option('page_for_posts');
  929. }
  930. // Point children of this page to its parent, also clean the cache of affected children
  931. $children_query = $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type='page'", $postid);
  932. $children = $wpdb->get_results($children_query);
  933. $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'page' ) );
  934. }
  935. // Do raw query. wp_get_post_revisions() is filtered
  936. $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
  937. // Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
  938. foreach ( $revision_ids as $revision_id )
  939. wp_delete_post_revision( $revision_id );
  940. // Point all attachments to this post up one level
  941. $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
  942. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
  943. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
  944. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d", $postid ));
  945. if ( 'page' == $post->post_type ) {
  946. clean_page_cache($postid);
  947. foreach ( (array) $children as $child )
  948. clean_page_cache($child->ID);
  949. $wp_rewrite->flush_rules();
  950. } else {
  951. clean_post_cache($postid);
  952. }
  953. do_action('deleted_post', $postid);
  954. return $post;
  955. }
  956. /**
  957. * wp_get_post_categories() - Retrieve the list of categories for a post
  958. *
  959. * Compatibility layer for themes and plugins. Also an easy layer of abstraction
  960. * away from the complexity of the taxonomy layer.
  961. *
  962. * @package WordPress
  963. * @subpackage Post
  964. * @since 2.1
  965. *
  966. * @uses wp_get_object_terms() Retrieves the categories. Args details can be found here
  967. *
  968. * @param int $post_id Optional. The Post ID
  969. * @param array $args Optional. Overwrite the defaults
  970. * @return array {@internal Missing Description}}
  971. */
  972. function wp_get_post_categories( $post_id = 0, $args = array() ) {
  973. $post_id = (int) $post_id;
  974. $defaults = array('fields' => 'ids');
  975. $args = wp_parse_args( $args, $defaults );
  976. $cats = wp_get_object_terms($post_id, 'category', $args);
  977. return $cats;
  978. }
  979. /**
  980. * wp_get_post_tags() - Retrieve the post tags
  981. *
  982. * @package WordPress
  983. * @subpackage Post
  984. * @since 2.3
  985. *
  986. * @uses wp_get_object_terms() Gets the tags for returning. Args can be found here
  987. *
  988. * @param int $post_id Optional. The Post ID
  989. * @param array $args Optional. Overwrite the defaults
  990. * @return mixed The tags the post has currently
  991. */
  992. function wp_get_post_tags( $post_id = 0, $args = array() ) {
  993. $post_id = (int) $post_id;
  994. $defaults = array('fields' => 'all');
  995. $args = wp_parse_args( $args, $defaults );
  996. $tags = wp_get_object_terms($post_id, 'post_tag', $args);
  997. return $tags;
  998. }
  999. /**
  1000. * wp_get_recent_posts() - Get the $num most recent posts
  1001. *
  1002. * {@internal Missing Long Description}}
  1003. *
  1004. * @package WordPress
  1005. * @subpackage Post
  1006. * @since 1.0.0
  1007. *
  1008. * @param int $num number of posts to get
  1009. * @return array {@internal Missing Description}}
  1010. */
  1011. function wp_get_recent_posts($num = 10) {
  1012. global $wpdb;
  1013. // Set the limit clause, if we got a limit
  1014. $num = (int) $num;
  1015. if ($num) {
  1016. $limit = "LIMIT $num";
  1017. }
  1018. $sql = "SELECT * FROM $wpdb->posts WHERE post_type = 'post' ORDER BY post_date DESC $limit";
  1019. $result = $wpdb->get_results($sql,ARRAY_A);
  1020. return $result?$result:array();
  1021. }
  1022. /**
  1023. * wp_get_single_post() - Get one post
  1024. *
  1025. * {@internal Missing Long Description}}
  1026. *
  1027. * @package WordPress
  1028. * @subpackage Post
  1029. * @since 1.0.0
  1030. * @uses $wpdb
  1031. *
  1032. * @param int $postid post ID
  1033. * @param string $mode How to return result, either OBJECT, ARRAY_N, or ARRAY_A
  1034. * @return object|array Post object or array holding post contents and information
  1035. */
  1036. function wp_get_single_post($postid = 0, $mode = OBJECT) {
  1037. $postid = (int) $postid;
  1038. $post = get_post($postid, $mode);
  1039. // Set categories and tags
  1040. if($mode == OBJECT) {
  1041. $post->post_category = wp_get_post_categories($postid);
  1042. $post->tags_input = wp_get_post_tags($postid, array('fields' => 'names'));
  1043. }
  1044. else {
  1045. $post['post_category'] = wp_get_post_categories($postid);
  1046. $post['tags_input'] = wp_get_post_tags($postid, array('fields' => 'names'));
  1047. }
  1048. return $post;
  1049. }
  1050. /**
  1051. * wp_insert_post() - Insert a post
  1052. *
  1053. * {@internal Missing Long Description}}
  1054. *
  1055. * @package WordPress
  1056. * @subpackage Post
  1057. * @since 1.0.0
  1058. *
  1059. * @uses $wpdb
  1060. * @uses $wp_rewrite
  1061. * @uses $user_ID
  1062. * @uses $allowedtags
  1063. *
  1064. * @param array $postarr post contents
  1065. * @return int post ID or 0 on error
  1066. */
  1067. function wp_insert_post($postarr = array(), $wp_error = false) {
  1068. global $wpdb, $wp_rewrite, $user_ID;
  1069. $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
  1070. 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
  1071. 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
  1072. 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '');
  1073. $postarr = wp_parse_args($postarr, $defaults);
  1074. $postarr = sanitize_post($postarr, 'db');
  1075. // export array as variables
  1076. extract($postarr, EXTR_SKIP);
  1077. // Are we updating or creating?
  1078. $update = false;
  1079. if ( !empty($ID) ) {
  1080. $update = true;
  1081. $previous_status = get_post_field('post_status', $ID);
  1082. } else {
  1083. $previous_status = 'new';
  1084. }
  1085. if ( ('' == $post_content) && ('' == $post_title) && ('' == $post_excerpt) ) {
  1086. if ( $wp_error )
  1087. return new WP_Error('empty_content', __('Content, title, and excerpt are empty.'));
  1088. else
  1089. return 0;
  1090. }
  1091. // Make sure we set a valid category
  1092. if (0 == count($post_category) || !is_array($post_category)) {
  1093. $post_category = array(get_option('default_category'));
  1094. }
  1095. if ( empty($post_author) )
  1096. $post_author = $user_ID;
  1097. if ( empty($post_status) )
  1098. $post_status = 'draft';
  1099. if ( empty($post_type) )
  1100. $post_type = 'post';
  1101. // Get the post ID and GUID
  1102. if ( $update ) {
  1103. $post_ID = (int) $ID;
  1104. $guid = get_post_field( 'guid', $post_ID );
  1105. }
  1106. // Create a valid post name. Drafts are allowed to have an empty
  1107. // post name.
  1108. if ( empty($post_name) ) {
  1109. if ( 'draft' != $post_status )
  1110. $post_name = sanitize_title($post_title);
  1111. } else {
  1112. $post_name = sanitize_title($post_name);
  1113. }
  1114. // If the post date is empty (due to having been new or a draft) and status is not 'draft', set date to now
  1115. if ( empty($post_date) || '0000-00-00 00:00:00' == $post_date ) {
  1116. if ( !in_array($post_status, array('draft', 'pending')) )
  1117. $post_date = current_time('mysql');
  1118. else
  1119. $post_date = '0000-00-00 00:00:00';
  1120. }
  1121. if ( empty($post_date_gmt) || '0000-00-00 00:00:00' == $post_date_gmt ) {
  1122. if ( !in_array($post_status, array('draft', 'pending')) )
  1123. $post_date_gmt = get_gmt_from_date($post_date);
  1124. else
  1125. $post_date_gmt = '0000-00-00 00:00:00';
  1126. }
  1127. if ( $update || '0000-00-00 00:00:00' == $post_date ) {
  1128. $post_modified = current_time( 'mysql' );
  1129. $post_modified_gmt = current_time( 'mysql', 1 );
  1130. } else {
  1131. $post_modified = $post_date;
  1132. $post_modified_gmt = $post_date_gmt;
  1133. }
  1134. if ( 'publish' == $post_status ) {
  1135. $now = gmdate('Y-m-d H:i:59');
  1136. if ( mysql2date('U', $post_date_gmt) > mysql2date('U', $now) )
  1137. $post_status = 'future';
  1138. }
  1139. if ( empty($comment_status) ) {
  1140. if ( $update )
  1141. $comment_status = 'closed';
  1142. else
  1143. $comment_status = get_option('default_comment_status');
  1144. }
  1145. if ( empty($ping_status) )
  1146. $ping_status = get_option('default_ping_status');
  1147. if ( isset($to_ping) )
  1148. $to_ping = preg_replace('|\s+|', "\n", $to_ping);
  1149. else
  1150. $to_ping = '';
  1151. if ( ! isset($pinged) )
  1152. $pinged = '';
  1153. if ( isset($post_parent) )
  1154. $post_parent = (int) $post_parent;
  1155. else
  1156. $post_parent = 0;
  1157. if ( isset($menu_order) )
  1158. $menu_order = (int) $menu_order;
  1159. else
  1160. $menu_order = 0;
  1161. if ( !isset($post_password) )
  1162. $post_password = '';
  1163. if ( 'draft' != $post_status ) {
  1164. $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $post_name, $post_type, $post_ID, $post_parent));
  1165. if ($post_name_check || in_array($post_name, $wp_rewrite->feeds) ) {
  1166. $suffix = 2;
  1167. do {
  1168. $alt_post_name = substr($post_name, 0, 200-(strlen($suffix)+1)). "-$suffix";
  1169. $post_name_check = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d AND post_parent = %d LIMIT 1", $alt_post_name, $post_type, $post_ID, $post_parent));
  1170. $suffix++;
  1171. } while ($post_name_check);
  1172. $post_name = $alt_post_name;
  1173. }
  1174. }
  1175. // expected_slashed (everything!)
  1176. $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'guid' ) );
  1177. $data = stripslashes_deep( $data );
  1178. $where = array( 'ID' => $post_ID );
  1179. if ($update) {
  1180. do_action( 'pre_post_update', $post_ID );
  1181. if ( false === $wpdb->update( $wpdb->posts, $data, $where ) ) {
  1182. if ( $wp_error )
  1183. return new WP_Error('db_update_error', __('Could not update post in the database'), $wpdb->last_error);
  1184. else
  1185. return 0;
  1186. }
  1187. } else {
  1188. $data['post_mime_type'] = stripslashes( $post_mime_type ); // This isn't in the update
  1189. if ( false === $wpdb->insert( $wpdb->posts, $data ) ) {
  1190. if ( $wp_error )
  1191. return new WP_Error('db_insert_error', __('Could not insert post into the database'), $wpdb->last_error);
  1192. else
  1193. return 0;
  1194. }
  1195. $post_ID = (int) $wpdb->insert_id;
  1196. // use the newly generated $post_ID
  1197. $where = array( 'ID' => $post_ID );
  1198. }
  1199. if ( empty($post_name) && 'draft' != $post_status ) {
  1200. $post_name = sanitize_title($post_title, $post_ID);
  1201. $wpdb->update( $wpdb->posts, compact( 'post_name' ), $where );
  1202. }
  1203. wp_set_post_categories( $post_ID, $post_category );
  1204. wp_set_post_tags( $post_ID, $tags_input );
  1205. $current_guid = get_post_field( 'guid', $post_ID );
  1206. if ( 'page' == $post_type )
  1207. clean_page_cache($post_ID);
  1208. else
  1209. clean_post_cache($post_ID);
  1210. // Set GUID
  1211. if ( !$update && '' == $current_guid )
  1212. $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
  1213. $post = get_post($post_ID);
  1214. if ( !empty($page_template) && 'page' == $post_type ) {
  1215. $post->page_template = $page_template;
  1216. $page_templates = get_page_templates();
  1217. if ( 'default' != $page_template && !in_array($page_template, $page_templates) ) {
  1218. if ( $wp_error )
  1219. return new WP_Error('invalid_page_template', __('The page template is invalid.'));
  1220. else
  1221. return 0;
  1222. }
  1223. update_post_meta($post_ID, '_wp_page_template', $page_template);
  1224. }
  1225. wp_transition_post_status($post_status, $previous_status, $post);
  1226. if ( $update)
  1227. do_action('edit_post', $post_ID, $post);
  1228. do_action('save_post', $post_ID, $post);
  1229. do_action('wp_insert_post', $post_ID, $post);
  1230. return $post_ID;
  1231. }
  1232. /**
  1233. * wp_update_post() - Update a post
  1234. *
  1235. * {@internal Missing Long Description}}
  1236. *
  1237. * @package WordPress
  1238. * @subpackage Post
  1239. * @since 1.0.0
  1240. * @uses $wpdb
  1241. *
  1242. * @param array $postarr post data
  1243. * @return int {@internal Missing Description}}
  1244. */
  1245. function wp_update_post($postarr = array()) {
  1246. if ( is_object($postarr) )
  1247. $postarr = get_object_vars($postarr);
  1248. // First, get all of the original fields
  1249. $post = wp_get_single_post($postarr['ID'], ARRAY_A);
  1250. // Escape data pulled from DB.
  1251. $post = add_magic_quotes($post);
  1252. // Passed post category list overwrites existing category list if not empty.
  1253. if ( isset($postarr['post_category']) && is_array($postarr['post_category'])
  1254. && 0 != count($postarr['post_category']) )
  1255. $post_cats = $postarr['post_category'];
  1256. else
  1257. $post_cats = $post['post_category'];
  1258. // Drafts shouldn't be assigned a date unless explicitly done so by the user
  1259. if ( in_array($post['post_status'], array('draft', 'pending')) && empty($postarr['edit_date']) && empty($postarr['post_date']) &&
  1260. ('0000-00-00 00:00:00' == $post['post_date']) )
  1261. $clear_date = true;
  1262. else
  1263. $clear_date = false;
  1264. // Merge old and new fields with new fields overwriting old ones.
  1265. $postarr = array_merge($post, $postarr);
  1266. $postarr['post_category'] = $post_cats;
  1267. if ( $clear_date ) {
  1268. $postarr['post_date'] = '';
  1269. $postarr['post_date_gmt'] = '';
  1270. }
  1271. if ($postarr['post_type'] == 'attachment')
  1272. return wp_insert_attachment($postarr);
  1273. return wp_insert_post($postarr);
  1274. }
  1275. /**
  1276. * wp_publish_post() - Mark a post as "published"
  1277. *
  1278. * {@internal Missing Long Description}}
  1279. *
  1280. * @package WordPress
  1281. * @subpackage Post
  1282. * @since 2.1
  1283. * @uses $wpdb
  1284. *
  1285. * @param int $post_id Post ID
  1286. * @return int|null {@internal Missing Description}}
  1287. */
  1288. function wp_publish_post($post_id) {
  1289. global $wpdb;
  1290. $post = get_post($post_id);
  1291. if ( empty($post) )
  1292. return;
  1293. if ( 'publish' == $post->post_status )
  1294. return;
  1295. $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post_id ) );
  1296. $old_status = $post->post_status;
  1297. $post->post_status = 'publish';
  1298. wp_transition_post_status('publish', $old_status, $post);
  1299. // Update counts for the post's terms.
  1300. foreach ( get_object_taxonomies('post') as $taxonomy ) {
  1301. $terms = wp_get_object_terms($post_id, $taxonomy, 'fields=tt_ids');
  1302. wp_update_term_count($terms, $taxonomy);
  1303. }
  1304. do_action('edit_post', $post_id, $post);
  1305. do_action('save_post', $post_id, $post);
  1306. do_action('wp_insert_post', $post_id, $post);
  1307. }
  1308. /**
  1309. * check_and_publish_future_post() - check to make sure post has correct status before
  1310. * passing it on to be published. Invoked by cron 'publish_future_post' event
  1311. * This safeguard prevents cron from publishing drafts, etc.
  1312. *
  1313. * {@internal Missing Long Description}}
  1314. *
  1315. * @package WordPress
  1316. * @subpackage Post
  1317. * @since 2.5
  1318. * @uses $wpdb
  1319. *
  1320. * @param int $post_id Post ID
  1321. * @return int|null {@internal Missing Description}}
  1322. */
  1323. function check_and_publish_future_post($post_id) {
  1324. $post = get_post($post_id);
  1325. if ( empty($post) )
  1326. return;
  1327. if ( 'future' != $post->post_status )
  1328. return;
  1329. return wp_publish_post($post_id);
  1330. }
  1331. /**
  1332. * wp_add_post_tags() - Adds the tags to a post
  1333. *
  1334. * @uses wp_set_post_tags() Same first two paraeters, but the last parameter is always set to true.
  1335. *
  1336. * @package WordPress
  1337. * @subpackage Post
  1338. * @since 2.3
  1339. *
  1340. * @param int $post_id Optional. Post ID
  1341. * @param string $tags The tags to set for the post
  1342. * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
  1343. */
  1344. function wp_add_post_tags($post_id = 0, $tags = '') {
  1345. return wp_set_post_tags($post_id, $tags, true);
  1346. }
  1347. /**
  1348. * wp_set_post_tags() - Set the tags for a post
  1349. *
  1350. * {@internal Missing Long Description}}
  1351. *
  1352. * @package WordPress
  1353. * @subpackage Post
  1354. * @since 2.3
  1355. * @uses $wpdb
  1356. *
  1357. * @param int $post_id post ID
  1358. * @param string $tags The tags to set for the post
  1359. * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
  1360. * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
  1361. */
  1362. function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
  1363. $post_id = (int) $post_id;
  1364. if ( !$post_id )
  1365. return false;
  1366. if ( empty($tags) )
  1367. $tags = array();
  1368. $tags = (is_array($tags)) ? $tags : explode( ',', trim($tags, " \n\t\r\0\x0B,") );
  1369. wp_set_object_terms($post_id, $tags, 'post_tag', $append);
  1370. }
  1371. /**
  1372. * wp_set_post_categories() - Set categories for a post
  1373. *
  1374. * {@internal Missing Long Description}}
  1375. *
  1376. * @package WordPress
  1377. * @subpackage Post
  1378. * @since 2.1
  1379. * @uses $wpdb
  1380. *
  1381. * @param int $post_ID post ID
  1382. * @param array $post_categories
  1383. * @return bool|mixed {@internal Missing Description}}
  1384. */
  1385. function wp_set_post_categories($post_ID = 0, $post_categories = array()) {
  1386. $post_ID = (int) $post_ID;
  1387. // If $post_categories isn't already an array, make it one:
  1388. if (!is_array($post_categories) || 0 == count($post_categories) || empty($post_categories))
  1389. $post_categories = array(get_option('default_category'));
  1390. else if ( 1 == count($post_categories) && '' == $post_categories[0] )
  1391. return true;
  1392. $post_categories = array_map('intval', $post_categories);
  1393. $post_categories = array_unique($post_categories);
  1394. return wp_set_object_terms($post_ID, $post_categories, 'category');
  1395. } // wp_set_post_categories()
  1396. /**
  1397. * wp_transition_post_status() - Change the post transition status
  1398. *
  1399. * {@internal Missing Long Description}}
  1400. *
  1401. * @package WordPress
  1402. * @subpackage Post
  1403. * @since 2.3
  1404. *
  1405. * @param string $new_status {@internal Missing Description}}
  1406. * @param string $old_status {@internal Missing Description}}
  1407. * @param int $post {@internal Missing Description}}
  1408. */
  1409. function wp_transition_post_status($new_status, $old_status, $post) {
  1410. if ( $new_status != $old_status ) {
  1411. do_action('transition_post_status', $new_status, $old_status, $post);
  1412. do_action("${old_status}_to_$new_status", $post);
  1413. }
  1414. do_action("${new_status}_$post->post_type", $post->ID, $post);
  1415. }
  1416. //
  1417. // Trackback and ping functions
  1418. //
  1419. /**
  1420. * add_ping() - Add a URL to those already pung
  1421. *
  1422. * {@internal Missing Long Description}}
  1423. *
  1424. * @package WordPress
  1425. * @subpackage Post
  1426. * @since 1.5
  1427. * @uses $wpdb
  1428. *
  1429. * @param int $post_id post ID
  1430. * @param string $uri {@internal Missing Description}}
  1431. * @return mixed {@internal Missing Description}}
  1432. */
  1433. function add_ping($post_id, $uri) {
  1434. global $wpdb;
  1435. $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
  1436. $pung = trim($pung);
  1437. $pung = preg_split('/\s/', $pung);
  1438. $pung[] = $uri;
  1439. $new = implode("\n", $pung);
  1440. $new = apply_filters('add_ping', $new);
  1441. // expected_slashed ($new)
  1442. $new = stripslashes($new);
  1443. return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
  1444. }
  1445. /**
  1446. * get_enclosed() - Get enclosures already enclosed for a post
  1447. *
  1448. * {@internal Missing Long Description}}
  1449. *
  1450. * @package WordPress
  1451. * @subpackage Post
  1452. * @since 1.5
  1453. * @uses $wpdb
  1454. *
  1455. * @param int $post_id post ID
  1456. * @return array {@internal Missing Description}}
  1457. */
  1458. function get_enclosed($post_id) {
  1459. $custom_fields = get_post_custom( $post_id );
  1460. $pung = array();
  1461. if ( !is_array( $custom_fields ) )
  1462. return $pung;
  1463. foreach ( $custom_fields as $key => $val ) {
  1464. if ( 'enclosure' != $key || !is_array( $val ) )
  1465. continue;
  1466. foreach( $val as $enc ) {
  1467. $enclosure = split( "\n", $enc );
  1468. $pung[] = trim( $enclosure[ 0 ] );
  1469. }
  1470. }
  1471. $pung = apply_filters('get_enclosed', $pung);
  1472. return $pung;
  1473. }
  1474. /**
  1475. * get_pung() - Get URLs already pinged for a post
  1476. *
  1477. * {@internal Missing Long Description}}
  1478. *
  1479. * @package WordPress
  1480. * @subpackage Post
  1481. * @since 1.5
  1482. * @uses $wpdb
  1483. *
  1484. * @param int $post_id post ID
  1485. * @return array {@internal Missing Description}}
  1486. */
  1487. function get_pung($post_id) {
  1488. global $wpdb;
  1489. $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
  1490. $pung = trim($pung);
  1491. $pung = preg_split('/\s/', $pung);
  1492. $pung = apply_filters('get_pung', $pung);
  1493. return $pung;
  1494. }
  1495. /**
  1496. * get_to_ping() - Get any URLs in the todo list
  1497. *
  1498. * {@internal Missing Long Description}}
  1499. *
  1500. * @package WordPress
  1501. * @subpackage Post
  1502. * @since 1.5
  1503. * @uses $wpdb
  1504. *
  1505. * @param int $post_id post ID
  1506. * @return array {@internal Missing Description}}
  1507. */
  1508. function get_to_ping($post_id) {
  1509. global $wpdb;
  1510. $to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
  1511. $to_ping = trim($to_ping);
  1512. $to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
  1513. $to_ping = apply_filters('get_to_ping', $to_ping);
  1514. return $to_ping;
  1515. }
  1516. /**
  1517. * trackback_url_list() - Do trackbacks for a list of urls
  1518. *
  1519. * {@internal Missing Long Description}}
  1520. *
  1521. * @package WordPress
  1522. * @subpackage Post
  1523. * @since 1.0.0
  1524. *
  1525. * @param string $tb_list comma separated list of URLs
  1526. * @param int $post_id post ID
  1527. */
  1528. function trackback_url_list($tb_list, $post_id) {
  1529. if (!empty($tb_list)) {
  1530. // get post data
  1531. $postdata = wp_get_single_post($post_id, ARRAY_A);
  1532. // import postdata as variables
  1533. extract($postdata, EXTR_SKIP);
  1534. // form an excerpt
  1535. $excerpt = strip_tags($post_excerpt?$post_excerpt:$post_content);
  1536. if (strlen($excerpt) > 255) {
  1537. $excerpt = substr($excerpt,0,252) . '...';
  1538. }
  1539. $trackback_urls = explode(',', $tb_list);
  1540. foreach($trackback_urls as $tb_url) {
  1541. $tb_url = trim($tb_url);
  1542. trackback($tb_url, stripslashes($post_title), $excerpt, $post_id);
  1543. }
  1544. }
  1545. }
  1546. //
  1547. // Page functions
  1548. //
  1549. /**
  1550. * get_all_page_ids() - Get a list of page IDs
  1551. *
  1552. * {@internal Missing Long Description}}
  1553. *
  1554. * @package WordPress
  1555. * @subpackage Post
  1556. * @since 2.0
  1557. * @uses $wpdb
  1558. *
  1559. * @return array {@internal Missing Description}}
  1560. */
  1561. function get_all_page_ids() {
  1562. global $wpdb;
  1563. if ( ! $page_ids = wp_cache_get('all_page_ids', 'posts') ) {
  1564. $page_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'page'");
  1565. wp_cache_add('all_page_ids', $page_ids, 'posts');
  1566. }
  1567. return $page_ids;
  1568. }
  1569. /**
  1570. * get_page() - Retrieves page data given a page ID or page object
  1571. *
  1572. * {@internal Missing Long Description}}
  1573. *
  1574. * @package WordPress
  1575. * @subpackage Post
  1576. * @since 1.5.1
  1577. *
  1578. * @param mixed &$page page object or page ID
  1579. * @param string $output what to output
  1580. * @param string $filter How the return value should be filtered.
  1581. * @return mixed {@internal Missing Description}}
  1582. */
  1583. function &get_page(&$page, $output = OBJECT, $filter = 'raw') {
  1584. if ( empty($page) ) {
  1585. if ( isset( $GLOBALS['page'] ) && isset( $GLOBALS['page']->ID ) )
  1586. return get_post($GLOBALS['page'], $output, $filter);
  1587. else
  1588. return null;
  1589. }
  1590. return get_post($page, $output, $filter);
  1591. }
  1592. /**
  1593. * get_page_by_path() - Retrieves a page given its path
  1594. *
  1595. * {@internal Missing Long Description}}
  1596. *
  1597. * @package WordPress
  1598. * @subpackage Post
  1599. * @since 2.1
  1600. * @uses $wpdb
  1601. *
  1602. * @param string $page_path page path
  1603. * @param string $output output type
  1604. * @return mixed {@internal Missing Description}}
  1605. */
  1606. function get_page_by_path($page_path, $output = OBJECT) {
  1607. global $wpdb;
  1608. $page_path = rawurlencode(urldecode($page_path));
  1609. $page_path = str_replace('%2F', '/', $page_path);
  1610. $page_path = str_replace('%20', ' ', $page_path);
  1611. $page_paths = '/' . trim($page_path, '/');
  1612. $leaf_path = sanitize_title(basename($page_paths));
  1613. $page_paths = explode('/', $page_paths);
  1614. foreach($page_paths as $pathdir)
  1615. $full_path .= ($pathdir!=''?'/':'') . sanitize_title($pathdir);
  1616. $pages = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_name = %s AND (post_type = 'page' OR post_type = 'attachment')", $leaf_path ));
  1617. if ( empty($pages) )
  1618. return NULL;
  1619. foreach ($pages as $page) {
  1620. $path = '/' . $leaf_path;
  1621. $curpage = $page;
  1622. while ($curpage->post_parent != 0) {
  1623. $curpage = $wpdb->get_row( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE ID = %d and post_type='page'", $curpage->post_parent ));
  1624. $path = '/' . $curpage->post_name . $path;
  1625. }
  1626. if ( $path == $full_path )
  1627. return get_page($page->ID, $output);
  1628. }
  1629. return NULL;
  1630. }
  1631. /**
  1632. * get_page_by_title() - Retrieve a page given its title
  1633. *
  1634. * {@internal Missing Long Description}}
  1635. *
  1636. * @package WordPress
  1637. * @subpackage Post
  1638. * @since 2.1
  1639. * @uses $wpdb
  1640. *
  1641. * @param string $page_title page title
  1642. * @param string $output output type
  1643. * @return mixed {@internal Missing Description}}
  1644. */
  1645. function get_page_by_title($page_title, $output = OBJECT) {
  1646. global $wpdb;
  1647. $page = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type='page'", $page_title ));
  1648. if ( $page )
  1649. return get_page($page, $output);
  1650. return NULL;
  1651. }
  1652. /**
  1653. * get_page_children() - Retrieve child pages
  1654. *
  1655. * {@internal Missing Long Description}}
  1656. *
  1657. * @package WordPress
  1658. * @subpackage Post
  1659. * @since 1.5.1
  1660. *
  1661. * @param int $page_id page ID
  1662. * @param array $pages list of pages
  1663. * @return array {@internal Missing Description}}
  1664. */
  1665. function &get_page_children($page_id, $pages) {
  1666. $page_list = array();
  1667. foreach ( $pages as $page ) {
  1668. if ( $page->post_parent == $page_id ) {
  1669. $page_list[] = $page;
  1670. if ( $children = get_page_children($page->ID, $pages) )
  1671. $page_list = array_merge($page_list, $children);
  1672. }
  1673. }
  1674. return $page_list;
  1675. }
  1676. /**
  1677. * get_page_hierarchy() - {@internal Missing Short Description}}
  1678. *
  1679. * Fetches the pages returned as a FLAT list, but arranged in order of their hierarchy,
  1680. * i.e., child parents immediately follow their parents.
  1681. *
  1682. * @package WordPress
  1683. * @subpackage Post
  1684. * @since 2.0
  1685. *
  1686. * @param array $posts posts array
  1687. * @param int $parent parent page ID
  1688. * @return array {@internal Missing Description}}
  1689. */
  1690. function get_page_hierarchy($posts, $parent = 0) {
  1691. $result = array ( );
  1692. if ($posts) { foreach ($posts as $post) {
  1693. if ($post->post_parent == $parent) {
  1694. $result[$post->ID] = $post->post_name;
  1695. $children = get_page_hierarchy($posts, $post->ID);
  1696. $result += $children; //append $children to $result
  1697. }
  1698. } }
  1699. return $result;
  1700. }
  1701. /**
  1702. * get_page_uri() - Builds a page URI
  1703. *
  1704. * {@internal Missing Long Description}}
  1705. *
  1706. * @package WordPress
  1707. * @subpackage Post
  1708. * @since 1.5
  1709. *
  1710. * @param int $page_id page ID
  1711. * @return string {@internal Missing Description}}
  1712. */
  1713. function get_page_uri($page_id) {
  1714. $page = get_page($page_id);
  1715. $uri = $page->post_name;
  1716. // A page cannot be it's own parent.
  1717. if ( $page->post_parent == $page->ID )
  1718. return $uri;
  1719. while ($page->post_parent != 0) {
  1720. $page = get_page($page->post_parent);
  1721. $uri = $page->post_name . "/" . $uri;
  1722. }
  1723. return $uri;
  1724. }
  1725. /**
  1726. * get_pages() - Retrieve a list of pages
  1727. *
  1728. * {@internal Missing Long Description}}
  1729. *
  1730. * @package WordPress
  1731. * @subpackage Post
  1732. * @since 1.5
  1733. * @uses $wpdb
  1734. *
  1735. * @param mixed $args Optional. Array or string of options
  1736. * @return array List of pages matching defaults or $args
  1737. */
  1738. function &get_pages($args = '') {
  1739. global $wpdb;
  1740. $defaults = array(
  1741. 'child_of' => 0, 'sort_order' => 'ASC',
  1742. 'sort_column' => 'post_title', 'hierarchical' => 1,
  1743. 'exclude' => '', 'include' => '',
  1744. 'meta_key' => '', 'meta_value' => '',
  1745. 'authors' => ''
  1746. );
  1747. $r = wp_parse_args( $args, $defaults );
  1748. extract( $r, EXTR_SKIP );
  1749. $key = md5( serialize( $r ) );
  1750. if ( $cache = wp_cache_get( 'get_pages', 'posts' ) )
  1751. if ( isset( $cache[ $key ] ) )
  1752. return apply_filters('get_pages', $cache[ $key ], $r );
  1753. $inclusions = '';
  1754. if ( !empty($include) ) {
  1755. $child_of = 0; //ignore child_of, exclude, meta_key, and meta_value params if using include
  1756. $exclude = '';
  1757. $meta_key = '';
  1758. $meta_value = '';
  1759. $hierarchical = false;
  1760. $incpages = preg_split('/[\s,]+/',$include);
  1761. if ( count($incpages) ) {
  1762. foreach ( $incpages as $incpage ) {
  1763. if (empty($inclusions))
  1764. $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpage);
  1765. else
  1766. $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpage);
  1767. }
  1768. }
  1769. }
  1770. if (!empty($inclusions))
  1771. $inclusions .= ')';
  1772. $exclusions = '';
  1773. if ( !empty($exclude) ) {
  1774. $expages = preg_split('/[\s,]+/',$exclude);
  1775. if ( count($expages) ) {
  1776. foreach ( $expages as $expage ) {
  1777. if (empty($exclusions))
  1778. $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expage);
  1779. else
  1780. $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expage);
  1781. }
  1782. }
  1783. }
  1784. if (!empty($exclusions))
  1785. $exclusions .= ')';
  1786. $author_query = '';
  1787. if (!empty($authors)) {
  1788. $post_authors = preg_split('/[\s,]+/',$authors);
  1789. if ( count($post_authors) ) {
  1790. foreach ( $post_authors as $post_author ) {
  1791. //Do we have an author id or an author login?
  1792. if ( 0 == intval($post_author) ) {
  1793. $post_author = get_userdatabylogin($post_author);
  1794. if ( empty($post_author) )
  1795. continue;
  1796. if ( empty($post_author->ID) )
  1797. continue;
  1798. $post_author = $post_author->ID;
  1799. }
  1800. if ( '' == $author_query )
  1801. $author_query = $wpdb->prepare(' post_author = %d ', $post_author);
  1802. else
  1803. $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author);
  1804. }
  1805. if ( '' != $author_query )
  1806. $author_query = " AND ($author_query)";
  1807. }
  1808. }
  1809. $join = '';
  1810. $where = "$exclusions $inclusions ";
  1811. if ( ! empty( $meta_key ) || ! empty( $meta_value ) ) {
  1812. $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
  1813. // meta_key and met_value might be slashed
  1814. $meta_key = stripslashes($meta_key);
  1815. $meta_value = stripslashes($meta_value);
  1816. if ( ! empty( $meta_key ) )
  1817. $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
  1818. if ( ! empty( $meta_value ) )
  1819. $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
  1820. }
  1821. $query = "SELECT * FROM $wpdb->posts $join WHERE (post_type = 'page' AND post_status = 'publish') $where ";
  1822. $query .= $author_query;
  1823. $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
  1824. $pages = $wpdb->get_results($query);
  1825. if ( empty($pages) )
  1826. return apply_filters('get_pages', array(), $r);
  1827. // Update cache.
  1828. update_page_cache($pages);
  1829. if ( $child_of || $hierarchical )
  1830. $pages = & get_page_children($child_of, $pages);
  1831. $cache[ $key ] = $pages;
  1832. wp_cache_set( 'get_pages', $cache, 'posts' );
  1833. $pages = apply_filters('get_pages', $pages, $r);
  1834. return $pages;
  1835. }
  1836. //
  1837. // Attachment functions
  1838. //
  1839. /**
  1840. * is_local_attachment() - Check if the attachment URI is local one and is really an attachment.
  1841. *
  1842. * {@internal Missing Long Description}}
  1843. *
  1844. * @package WordPress
  1845. * @subpackage Post
  1846. * @since 2.0
  1847. *
  1848. * @param string $url URL to check
  1849. * @return bool {@internal Missing Description}}
  1850. */
  1851. function is_local_attachment($url) {
  1852. if (strpos($url, get_bloginfo('url')) === false)
  1853. return false;
  1854. if (strpos($url, get_bloginfo('url') . '/?attachment_id=') !== false)
  1855. return true;
  1856. if ( $id = url_to_postid($url) ) {
  1857. $post = & get_post($id);
  1858. if ( 'attachment' == $post->post_type )
  1859. return true;
  1860. }
  1861. return false;
  1862. }
  1863. /**
  1864. * wp_insert_attachment() - Insert an attachment
  1865. *
  1866. * {@internal Missing Long Description}}
  1867. *
  1868. * @package WordPress
  1869. * @subpackage Post
  1870. * @since 2.0
  1871. *
  1872. * @uses $wpdb
  1873. * @uses $user_ID
  1874. *
  1875. * @param object $object attachment object
  1876. * @param string $file filename
  1877. * @param int $post_parent parent post ID
  1878. * @return int {@internal Missing Description}}
  1879. */
  1880. function wp_insert_attachment($object, $file = false, $parent = 0) {
  1881. global $wpdb, $user_ID;
  1882. $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
  1883. 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
  1884. 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
  1885. 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '');
  1886. $object = wp_parse_args($object, $defaults);
  1887. if ( !empty($parent) )
  1888. $object['post_parent'] = $parent;
  1889. $object = sanitize_post($object, 'db');
  1890. // export array as variables
  1891. extract($object, EXTR_SKIP);
  1892. // Make sure we set a valid category
  1893. if (0 == count($post_category) || !is_array($post_category)) {
  1894. $post_category = array(get_option('default_category'));
  1895. }
  1896. if ( empty($post_author) )
  1897. $post_author = $user_ID;
  1898. $post_type = 'attachment';
  1899. $post_status = 'inherit';
  1900. // Are we updating or creating?
  1901. $update = false;
  1902. if ( !empty($ID) ) {
  1903. $update = true;
  1904. $post_ID = (int) $ID;
  1905. }
  1906. // Create a valid post name.
  1907. if ( empty($post_name) )
  1908. $post_name = sanitize_title($post_title);
  1909. else
  1910. $post_name = sanitize_title($post_name);
  1911. // expected_slashed ($post_name)
  1912. $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = '$post_name' AND post_status = 'inherit' AND ID != %d LIMIT 1", $post_ID));
  1913. if ($post_name_check) {
  1914. $suffix = 2;
  1915. while ($post_name_check) {
  1916. $alt_post_name = $post_name . "-$suffix";
  1917. // expected_slashed ($alt_post_name, $post_name)
  1918. $post_name_check = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name = '$alt_post_name' AND post_status = 'inherit' AND ID != %d AND post_parent = %d LIMIT 1", $post_ID, $post_parent));
  1919. $suffix++;
  1920. }
  1921. $post_name = $alt_post_name;
  1922. }
  1923. if ( empty($post_date) )
  1924. $post_date = current_time('mysql');
  1925. if ( empty($post_date_gmt) )
  1926. $post_date_gmt = current_time('mysql', 1);
  1927. if ( empty($post_modified) )
  1928. $post_modified = $post_date;
  1929. if ( empty($post_modified_gmt) )
  1930. $post_modified_gmt = $post_date_gmt;
  1931. if ( empty($comment_status) ) {
  1932. if ( $update )
  1933. $comment_status = 'closed';
  1934. else
  1935. $comment_status = get_option('default_comment_status');
  1936. }
  1937. if ( empty($ping_status) )
  1938. $ping_status = get_option('default_ping_status');
  1939. if ( isset($to_ping) )
  1940. $to_ping = preg_replace('|\s+|', "\n", $to_ping);
  1941. else
  1942. $to_ping = '';
  1943. if ( isset($post_parent) )
  1944. $post_parent = (int) $post_parent;
  1945. else
  1946. $post_parent = 0;
  1947. if ( isset($menu_order) )
  1948. $menu_order = (int) $menu_order;
  1949. else
  1950. $menu_order = 0;
  1951. if ( !isset($post_password) )
  1952. $post_password = '';
  1953. if ( ! isset($pinged) )
  1954. $pinged = '';
  1955. // expected_slashed (everything!)
  1956. $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ) );
  1957. $data = stripslashes_deep( $data );
  1958. if ( $update ) {
  1959. $wpdb->update( $wpdb->posts, $data, array( 'ID' => $post_ID ) );
  1960. } else {
  1961. $wpdb->insert( $wpdb->posts, $data );
  1962. $post_ID = (int) $wpdb->insert_id;
  1963. }
  1964. if ( empty($post_name) ) {
  1965. $post_name = sanitize_title($post_title, $post_ID);
  1966. $wpdb->update( $wpdb->posts, compact("post_name"), array( 'ID' => $post_ID ) );
  1967. }
  1968. wp_set_post_categories($post_ID, $post_category);
  1969. if ( $file )
  1970. update_attached_file( $post_ID, $file );
  1971. clean_post_cache($post_ID);
  1972. if ( $update) {
  1973. do_action('edit_attachment', $post_ID);
  1974. } else {
  1975. do_action('add_attachment', $post_ID);
  1976. }
  1977. return $post_ID;
  1978. }
  1979. /**
  1980. * wp_delete_attachment() - Delete an attachment
  1981. *
  1982. * {@internal Missing Long Description}}
  1983. *
  1984. * @package WordPress
  1985. * @subpackage Post
  1986. * @since 2.0
  1987. * @uses $wpdb
  1988. *
  1989. * @param int $postid attachment Id
  1990. * @return mixed {@internal Missing Description}}
  1991. */
  1992. function wp_delete_attachment($postid) {
  1993. global $wpdb;
  1994. if ( !$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
  1995. return $post;
  1996. if ( 'attachment' != $post->post_type )
  1997. return false;
  1998. $meta = wp_get_attachment_metadata( $postid );
  1999. $file = get_attached_file( $postid );
  2000. /** @todo Delete for pluggable post taxonomies too */
  2001. wp_delete_object_term_relationships($postid, array('category', 'post_tag'));
  2002. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->posts WHERE ID = %d", $postid ));
  2003. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
  2004. $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
  2005. if ( ! empty($meta['thumb']) ) {
  2006. // Don't delete the thumb if another attachment uses it
  2007. if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%'.$meta['thumb'].'%', $postid)) ) {
  2008. $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
  2009. $thumbfile = apply_filters('wp_delete_file', $thumbfile);
  2010. @ unlink($thumbfile);
  2011. }
  2012. }
  2013. // remove intermediate images if there are any
  2014. $sizes = apply_filters('intermediate_image_sizes', array('thumbnail', 'medium'));
  2015. foreach ( $sizes as $size ) {
  2016. if ( $intermediate = image_get_intermediate_size($postid, $size) ) {
  2017. $intermediate_file = apply_filters('wp_delete_file', $intermediate['path']);
  2018. @ unlink($intermediate_file);
  2019. }
  2020. }
  2021. $file = apply_filters('wp_delete_file', $file);
  2022. if ( ! empty($file) )
  2023. @ unlink($file);
  2024. clean_post_cache($postid);
  2025. do_action('delete_attachment', $postid);
  2026. return $post;
  2027. }
  2028. /**
  2029. * wp_get_attachment_metadata() - Retrieve metadata for an attachment
  2030. *
  2031. * {@internal Missing Long Description}}
  2032. *
  2033. * @package WordPress
  2034. * @subpackage Post
  2035. * @since 2.1
  2036. *
  2037. * @param int $post_id attachment ID
  2038. * @param bool $unfiltered Optional, default is false. If true, filters are not run
  2039. * @return array {@internal Missing Description}}
  2040. */
  2041. function wp_get_attachment_metadata( $post_id, $unfiltered = false ) {
  2042. $post_id = (int) $post_id;
  2043. if ( !$post =& get_post( $post_id ) )
  2044. return false;
  2045. $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
  2046. if ( $unfiltered )
  2047. return $data;
  2048. return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
  2049. }
  2050. /**
  2051. * wp_update_attachment_metadata() - Update metadata for an attachment
  2052. *
  2053. * {@internal Missing Long Description}}
  2054. *
  2055. * @package WordPress
  2056. * @subpackage Post
  2057. * @since 2.1
  2058. *
  2059. * @param int $post_id attachment ID
  2060. * @param array $data attachment data
  2061. * @return int {@internal Missing Description}}
  2062. */
  2063. function wp_update_attachment_metadata( $post_id, $data ) {
  2064. $post_id = (int) $post_id;
  2065. if ( !$post =& get_post( $post_id ) )
  2066. return false;
  2067. $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID );
  2068. return update_post_meta( $post->ID, '_wp_attachment_metadata', $data);
  2069. }
  2070. /**
  2071. * wp_get_attachment_url() - Retrieve the URL for an attachment
  2072. *
  2073. * {@internal Missing Long Description}}
  2074. *
  2075. * @package WordPress
  2076. * @subpackage Post
  2077. * @since 2.1
  2078. *
  2079. * @param int $post_id attachment ID
  2080. * @return string {@internal Missing Description}}
  2081. */
  2082. function wp_get_attachment_url( $post_id = 0 ) {
  2083. $post_id = (int) $post_id;
  2084. if ( !$post =& get_post( $post_id ) )
  2085. return false;
  2086. $url = get_the_guid( $post->ID );
  2087. if ( 'attachment' != $post->post_type || !$url )
  2088. return false;
  2089. return apply_filters( 'wp_get_attachment_url', $url, $post->ID );
  2090. }
  2091. /**
  2092. * wp_get_attachment_thumb_file() - Retrieve thumbnail for an attachment
  2093. *
  2094. * {@internal Missing Long Description}}
  2095. *
  2096. * @package WordPress
  2097. * @subpackage Post
  2098. * @since 2.1
  2099. *
  2100. * @param int $post_id attachment ID
  2101. * @return mixed {@internal Missing Description}}
  2102. */
  2103. function wp_get_attachment_thumb_file( $post_id = 0 ) {
  2104. $post_id = (int) $post_id;
  2105. if ( !$post =& get_post( $post_id ) )
  2106. return false;
  2107. if ( !is_array( $imagedata = wp_get_attachment_metadata( $post->ID ) ) )
  2108. return false;
  2109. $file = get_attached_file( $post->ID );
  2110. if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) )
  2111. return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
  2112. return false;
  2113. }
  2114. /**
  2115. * wp_get_attachment_thumb_url() - Retrieve URL for an attachment thumbnail
  2116. *
  2117. * {@internal Missing Long Description}}
  2118. *
  2119. * @package WordPress
  2120. * @subpackage Post
  2121. * @since 2.1
  2122. *
  2123. * @param int $post_id attachment ID
  2124. * @return string {@internal Missing Description}}
  2125. */
  2126. function wp_get_attachment_thumb_url( $post_id = 0 ) {
  2127. $post_id = (int) $post_id;
  2128. if ( !$post =& get_post( $post_id ) )
  2129. return false;
  2130. if ( !$url = wp_get_attachment_url( $post->ID ) )
  2131. return false;
  2132. $sized = image_downsize( $post_id, 'thumbnail' );
  2133. if ( $sized )
  2134. return $sized[0];
  2135. if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
  2136. return false;
  2137. $url = str_replace(basename($url), basename($thumb), $url);
  2138. return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
  2139. }
  2140. /**
  2141. * wp_attachment_is_image() - Check if the attachment is an image
  2142. *
  2143. * {@internal Missing Long Description}}
  2144. *
  2145. * @package WordPress
  2146. * @subpackage Post
  2147. * @since 2.1
  2148. *
  2149. * @param int $post_id attachment ID
  2150. * @return bool {@internal Missing Description}}
  2151. */
  2152. function wp_attachment_is_image( $post_id = 0 ) {
  2153. $post_id = (int) $post_id;
  2154. if ( !$post =& get_post( $post_id ) )
  2155. return false;
  2156. if ( !$file = get_attached_file( $post->ID ) )
  2157. return false;
  2158. $ext = preg_match('/\.([^.]+)$/', $file, $matches) ? strtolower($matches[1]) : false;
  2159. $image_exts = array('jpg', 'jpeg', 'gif', 'png');
  2160. if ( 'image/' == substr($post->post_mime_type, 0, 6) || $ext && 'import' == $post->post_mime_type && in_array($ext, $image_exts) )
  2161. return true;
  2162. return false;
  2163. }
  2164. /**
  2165. * wp_mime_type_icon() - Retrieve the icon for a MIME type
  2166. *
  2167. * {@internal Missing Long Description}}
  2168. *
  2169. * @package WordPress
  2170. * @subpackage Post
  2171. * @since 2.1
  2172. *
  2173. * @param string $mime MIME type
  2174. * @return string|bool {@internal Missing Description}}
  2175. */
  2176. function wp_mime_type_icon( $mime = 0 ) {
  2177. if ( !is_numeric($mime) )
  2178. $icon = wp_cache_get("mime_type_icon_$mime");
  2179. if ( empty($icon) ) {
  2180. $post_id = 0;
  2181. $post_mimes = array();
  2182. if ( is_numeric($mime) ) {
  2183. $mime = (int) $mime;
  2184. if ( $post =& get_post( $mime ) ) {
  2185. $post_id = (int) $post->ID;
  2186. $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $post->guid);
  2187. if ( !empty($ext) ) {
  2188. $post_mimes[] = $ext;
  2189. if ( $ext_type = wp_ext2type( $ext ) )
  2190. $post_mimes[] = $ext_type;
  2191. }
  2192. $mime = $post->post_mime_type;
  2193. } else {
  2194. $mime = 0;
  2195. }
  2196. } else {
  2197. $post_mimes[] = $mime;
  2198. }
  2199. $icon_files = wp_cache_get('icon_files');
  2200. if ( !is_array($icon_files) ) {
  2201. $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
  2202. $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url('images/crystal') );
  2203. $dirs = apply_filters( 'icon_dirs', array($icon_dir => $icon_dir_uri) );
  2204. $icon_files = array();
  2205. while ( $dirs ) {
  2206. $dir = array_shift($keys = array_keys($dirs));
  2207. $uri = array_shift($dirs);
  2208. if ( $dh = opendir($dir) ) {
  2209. while ( false !== $file = readdir($dh) ) {
  2210. $file = basename($file);
  2211. if ( substr($file, 0, 1) == '.' )
  2212. continue;
  2213. if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
  2214. if ( is_dir("$dir/$file") )
  2215. $dirs["$dir/$file"] = "$uri/$file";
  2216. continue;
  2217. }
  2218. $icon_files["$dir/$file"] = "$uri/$file";
  2219. }
  2220. closedir($dh);
  2221. }
  2222. }
  2223. wp_cache_set('icon_files', $icon_files, 600);
  2224. }
  2225. // Icon basename - extension = MIME wildcard
  2226. foreach ( $icon_files as $file => $uri )
  2227. $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
  2228. if ( ! empty($mime) ) {
  2229. $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
  2230. $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
  2231. $post_mimes[] = str_replace('/', '_', $mime);
  2232. }
  2233. $matches = wp_match_mime_types(array_keys($types), $post_mimes);
  2234. $matches['default'] = array('default');
  2235. foreach ( $matches as $match => $wilds ) {
  2236. if ( isset($types[$wilds[0]])) {
  2237. $icon = $types[$wilds[0]];
  2238. if ( !is_numeric($mime) )
  2239. wp_cache_set("mime_type_icon_$mime", $icon);
  2240. break;
  2241. }
  2242. }
  2243. }
  2244. return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id ); // Last arg is 0 if function pass mime type.
  2245. }
  2246. /**
  2247. * wp_check_for_changed_slugs() - {@internal Missing Short Description}}
  2248. *
  2249. * {@internal Missing Long Description}}
  2250. *
  2251. * @package WordPress
  2252. * @subpackage Post
  2253. * @since 2.1
  2254. *
  2255. * @param int $post_id The Post ID
  2256. * @return int Same as $post_id
  2257. */
  2258. function wp_check_for_changed_slugs($post_id) {
  2259. if ( !isset($_POST['wp-old-slug']) || !strlen($_POST['wp-old-slug']) )
  2260. return $post_id;
  2261. $post = &get_post($post_id);
  2262. // we're only concerned with published posts
  2263. if ( $post->post_status != 'publish' || $post->post_type != 'post' )
  2264. return $post_id;
  2265. // only bother if the slug has changed
  2266. if ( $post->post_name == $_POST['wp-old-slug'] )
  2267. return $post_id;
  2268. $old_slugs = (array) get_post_meta($post_id, '_wp_old_slug');
  2269. // if we haven't added this old slug before, add it now
  2270. if ( !count($old_slugs) || !in_array($_POST['wp-old-slug'], $old_slugs) )
  2271. add_post_meta($post_id, '_wp_old_slug', $_POST['wp-old-slug']);
  2272. // if the new slug was used previously, delete it from the list
  2273. if ( in_array($post->post_name, $old_slugs) )
  2274. delete_post_meta($post_id, '_wp_old_slug', $post->post_name);
  2275. return $post_id;
  2276. }
  2277. /**
  2278. * get_private_posts_cap_sql() - {@internal Missing Short Description}}
  2279. *
  2280. * This function provides a standardized way to appropriately select on
  2281. * the post_status of posts/pages. The function will return a piece of
  2282. * SQL code that can be added to a WHERE clause; this SQL is constructed
  2283. * to allow all published posts, and all private posts to which the user
  2284. * has access.
  2285. *
  2286. * @package WordPress
  2287. * @subpackage Post
  2288. * @since 2.2
  2289. *
  2290. * @uses $user_ID
  2291. * @uses apply_filters() Call 'pub_priv_sql_capability' filter for plugins with different post types
  2292. *
  2293. * @param string $post_type currently only supports 'post' or 'page'.
  2294. * @return string SQL code that can be added to a where clause.
  2295. */
  2296. function get_private_posts_cap_sql($post_type) {
  2297. global $user_ID;
  2298. $cap = '';
  2299. // Private posts
  2300. if ($post_type == 'post') {
  2301. $cap = 'read_private_posts';
  2302. // Private pages
  2303. } elseif ($post_type == 'page') {
  2304. $cap = 'read_private_pages';
  2305. // Dunno what it is, maybe plugins have their own post type?
  2306. } else {
  2307. $cap = apply_filters('pub_priv_sql_capability', $cap);
  2308. if (empty($cap)) {
  2309. // We don't know what it is, filters don't change anything,
  2310. // so set the SQL up to return nothing.
  2311. return '1 = 0';
  2312. }
  2313. }
  2314. $sql = '(post_status = \'publish\'';
  2315. if (current_user_can($cap)) {
  2316. // Does the user have the capability to view private posts? Guess so.
  2317. $sql .= ' OR post_status = \'private\'';
  2318. } elseif (is_user_logged_in()) {
  2319. // Users can view their own private posts.
  2320. $sql .= ' OR post_status = \'private\' AND post_author = \'' . $user_ID . '\'';
  2321. }
  2322. $sql .= ')';
  2323. return $sql;
  2324. }
  2325. /**
  2326. * get_lastpostdate() - {@internal Missing Short Description}}
  2327. *
  2328. * {@internal Missing Long Description}}
  2329. *
  2330. * @package WordPress
  2331. * @subpackage Post
  2332. * @since 0.71
  2333. *
  2334. * @uses $wpdb
  2335. * @uses $blog_id
  2336. * @uses apply_filters() Calls 'get_lastpostdate' filter
  2337. *
  2338. * @global mixed $cache_lastpostdate Stores the last post date
  2339. * @global mixed $pagenow The current page being viewed
  2340. *
  2341. * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
  2342. * @return string The date of the last post.
  2343. */
  2344. function get_lastpostdate($timezone = 'server') {
  2345. global $cache_lastpostdate, $wpdb, $blog_id;
  2346. $add_seconds_server = date('Z');
  2347. if ( !isset($cache_lastpostdate[$blog_id][$timezone]) ) {
  2348. switch(strtolower($timezone)) {
  2349. case 'gmt':
  2350. $lastpostdate = $wpdb->get_var("SELECT post_date_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
  2351. break;
  2352. case 'blog':
  2353. $lastpostdate = $wpdb->get_var("SELECT post_date FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
  2354. break;
  2355. case 'server':
  2356. $lastpostdate = $wpdb->get_var("SELECT DATE_ADD(post_date_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1");
  2357. break;
  2358. }
  2359. $cache_lastpostdate[$blog_id][$timezone] = $lastpostdate;
  2360. } else {
  2361. $lastpostdate = $cache_lastpostdate[$blog_id][$timezone];
  2362. }
  2363. return apply_filters( 'get_lastpostdate', $lastpostdate, $timezone );
  2364. }
  2365. /**
  2366. * get_lastpostmodified() - {@internal Missing Short Description}}
  2367. *
  2368. * {@internal Missing Long Description}}
  2369. *
  2370. * @package WordPress
  2371. * @subpackage Post
  2372. * @since 1.2
  2373. *
  2374. * @uses $wpdb
  2375. * @uses $blog_id
  2376. * @uses apply_filters() Calls 'get_lastpostmodified' filter
  2377. *
  2378. * @global mixed $cache_lastpostmodified Stores the date the last post was modified
  2379. * @global mixed $pagenow The current page being viewed
  2380. *
  2381. * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
  2382. * @return string The date the post was last modified.
  2383. */
  2384. function get_lastpostmodified($timezone = 'server') {
  2385. global $cache_lastpostmodified, $wpdb, $blog_id;
  2386. $add_seconds_server = date('Z');
  2387. if ( !isset($cache_lastpostmodified[$blog_id][$timezone]) ) {
  2388. switch(strtolower($timezone)) {
  2389. case 'gmt':
  2390. $lastpostmodified = $wpdb->get_var("SELECT post_modified_gmt FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
  2391. break;
  2392. case 'blog':
  2393. $lastpostmodified = $wpdb->get_var("SELECT post_modified FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
  2394. break;
  2395. case 'server':
  2396. $lastpostmodified = $wpdb->get_var("SELECT DATE_ADD(post_modified_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' ORDER BY post_modified_gmt DESC LIMIT 1");
  2397. break;
  2398. }
  2399. $lastpostdate = get_lastpostdate($timezone);
  2400. if ( $lastpostdate > $lastpostmodified ) {
  2401. $lastpostmodified = $lastpostdate;
  2402. }
  2403. $cache_lastpostmodified[$blog_id][$timezone] = $lastpostmodified;
  2404. } else {
  2405. $lastpostmodified = $cache_lastpostmodified[$blog_id][$timezone];
  2406. }
  2407. return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
  2408. }
  2409. /**
  2410. * update_post_cache() - Updates posts in cache
  2411. *
  2412. * @usedby update_page_cache() update_page_cache() aliased by this function.
  2413. *
  2414. * @package WordPress
  2415. * @subpackage Cache
  2416. * @since 1.5.1
  2417. *
  2418. * @param array $posts Array of post objects
  2419. */
  2420. function update_post_cache(&$posts) {
  2421. if ( !$posts )
  2422. return;
  2423. foreach ( $posts as $post )
  2424. wp_cache_add($post->ID, $post, 'posts');
  2425. }
  2426. /**
  2427. * clean_post_cache() - Will clean the post in the cache
  2428. *
  2429. * Cleaning means delete from the cache of the post. Will call to clean
  2430. * the term object cache associated with the post ID.
  2431. *
  2432. * @package WordPress
  2433. * @subpackage Cache
  2434. * @since 2.0
  2435. *
  2436. * @uses do_action() Will call the 'clean_post_cache' hook action.
  2437. *
  2438. * @param int $id The Post ID in the cache to clean
  2439. */
  2440. function clean_post_cache($id) {
  2441. global $wpdb;
  2442. $id = (int) $id;
  2443. wp_cache_delete($id, 'posts');
  2444. wp_cache_delete($id, 'post_meta');
  2445. clean_object_term_cache($id, 'post');
  2446. wp_cache_delete( 'wp_get_archives', 'general' );
  2447. do_action('clean_post_cache', $id);
  2448. if ( $children = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d", $id) ) ) {
  2449. foreach( $children as $cid )
  2450. clean_post_cache( $cid );
  2451. }
  2452. }
  2453. /**
  2454. * update_page_cache() - Alias of update_post_cache()
  2455. *
  2456. * @see update_post_cache() Posts and pages are the same, alias is intentional
  2457. *
  2458. * @package WordPress
  2459. * @subpackage Cache
  2460. * @since 1.5.1
  2461. *
  2462. * @param array $pages list of page objects
  2463. */
  2464. function update_page_cache(&$pages) {
  2465. update_post_cache($pages);
  2466. }
  2467. /**
  2468. * clean_page_cache() - Will clean the page in the cache
  2469. *
  2470. * Clean (read: delete) page from cache that matches $id. Will also clean
  2471. * cache associated with 'all_page_ids' and 'get_pages'.
  2472. *
  2473. * @package WordPress
  2474. * @subpackage Cache
  2475. * @since 2.0
  2476. *
  2477. * @uses do_action() Will call the 'clean_page_cache' hook action.
  2478. *
  2479. * @param int $id Page ID to clean
  2480. */
  2481. function clean_page_cache($id) {
  2482. clean_post_cache($id);
  2483. wp_cache_delete( 'all_page_ids', 'posts' );
  2484. wp_cache_delete( 'get_pages', 'posts' );
  2485. do_action('clean_page_cache', $id);
  2486. }
  2487. /**
  2488. * update_post_caches() - Call major cache updating functions for list of Post objects.
  2489. *
  2490. * @package WordPress
  2491. * @subpackage Cache
  2492. * @since 1.5
  2493. *
  2494. * @uses $wpdb
  2495. * @uses update_post_cache()
  2496. * @uses update_object_term_cache()
  2497. * @uses update_postmeta_cache()
  2498. *
  2499. * @param array $posts Array of Post objects
  2500. */
  2501. function update_post_caches(&$posts) {
  2502. // No point in doing all this work if we didn't match any posts.
  2503. if ( !$posts )
  2504. return;
  2505. update_post_cache($posts);
  2506. $post_ids = array();
  2507. for ($i = 0; $i < count($posts); $i++)
  2508. $post_ids[] = $posts[$i]->ID;
  2509. update_object_term_cache($post_ids, 'post');
  2510. update_postmeta_cache($post_ids);
  2511. }
  2512. /**
  2513. * update_postmeta_cache() - {@internal Missing Short Description}}
  2514. *
  2515. * {@internal Missing Long Description}}
  2516. *
  2517. * @package WordPress
  2518. * @subpackage Cache
  2519. * @since 2.1
  2520. *
  2521. * @uses $wpdb
  2522. *
  2523. * @param array $post_ids {@internal Missing Description}}
  2524. * @return bool|array Returns false if there is nothing to update or an array of metadata
  2525. */
  2526. function update_postmeta_cache($post_ids) {
  2527. global $wpdb;
  2528. if ( empty( $post_ids ) )
  2529. return false;
  2530. if ( !is_array($post_ids) ) {
  2531. $post_ids = preg_replace('|[^0-9,]|', '', $post_ids);
  2532. $post_ids = explode(',', $post_ids);
  2533. }
  2534. $post_ids = array_map('intval', $post_ids);
  2535. $ids = array();
  2536. foreach ( (array) $post_ids as $id ) {
  2537. if ( false === wp_cache_get($id, 'post_meta') )
  2538. $ids[] = $id;
  2539. }
  2540. if ( empty( $ids ) )
  2541. return false;
  2542. // Get post-meta info
  2543. $id_list = join(',', $ids);
  2544. $cache = array();
  2545. if ( $meta_list = $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM $wpdb->postmeta WHERE post_id IN ($id_list) ORDER BY post_id, meta_key", ARRAY_A) ) {
  2546. foreach ( (array) $meta_list as $metarow) {
  2547. $mpid = (int) $metarow['post_id'];
  2548. $mkey = $metarow['meta_key'];
  2549. $mval = $metarow['meta_value'];
  2550. // Force subkeys to be array type:
  2551. if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
  2552. $cache[$mpid] = array();
  2553. if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
  2554. $cache[$mpid][$mkey] = array();
  2555. // Add a value to the current pid/key:
  2556. $cache[$mpid][$mkey][] = $mval;
  2557. }
  2558. }
  2559. foreach ( (array) $ids as $id ) {
  2560. if ( ! isset($cache[$id]) )
  2561. $cache[$id] = array();
  2562. }
  2563. foreach ( array_keys($cache) as $post)
  2564. wp_cache_set($post, $cache[$post], 'post_meta');
  2565. return $cache;
  2566. }
  2567. //
  2568. // Hooks
  2569. //
  2570. /**
  2571. * _transition_post_status() - Hook {@internal Missing Short Description}}
  2572. *
  2573. * {@internal Missing Long Description}}
  2574. *
  2575. * @package WordPress
  2576. * @subpackage Post
  2577. * @since 2.3
  2578. *
  2579. * @uses $wpdb
  2580. *
  2581. * @param string $new_status {@internal Missing Description}}
  2582. * @param string $old_status {@internal Missing Description}}
  2583. * @param object $post Object type containing the post information
  2584. */
  2585. function _transition_post_status($new_status, $old_status, $post) {
  2586. global $wpdb;
  2587. if ( $old_status != 'publish' && $new_status == 'publish' ) {
  2588. // Reset GUID if transitioning to publish and it is empty
  2589. if ( '' == get_the_guid($post->ID) )
  2590. $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
  2591. do_action('private_to_published', $post->ID); // Deprecated, use private_to_publish
  2592. }
  2593. // Always clears the hook in case the post status bounced from future to draft.
  2594. wp_clear_scheduled_hook('publish_future_post', $post->ID);
  2595. }
  2596. /**
  2597. * _future_post_hook() - Hook used to schedule publication for a post marked for the future.
  2598. *
  2599. * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
  2600. *
  2601. * @package WordPress
  2602. * @subpackage Post
  2603. * @since 2.3
  2604. *
  2605. * @param int $post_id Not Used. Can be set to null.
  2606. * @param object $post Object type containing the post information
  2607. */
  2608. function _future_post_hook($deprecated = '', $post) {
  2609. wp_clear_scheduled_hook( 'publish_future_post', $post->ID );
  2610. wp_schedule_single_event(strtotime($post->post_date_gmt. ' GMT'), 'publish_future_post', array($post->ID));
  2611. }
  2612. /**
  2613. * _publish_post_hook() - Hook {@internal Missing Short Description}}
  2614. *
  2615. * {@internal Missing Long Description}}
  2616. *
  2617. * @package WordPress
  2618. * @subpackage Post
  2619. * @since 2.3
  2620. *
  2621. * @uses $wpdb
  2622. * @uses XMLRPC_REQUEST
  2623. * @uses APP_REQUEST
  2624. * @uses do_action Calls 'xmlprc_publish_post' action if XMLRPC_REQUEST is defined. Calls 'app_publish_post'
  2625. * action if APP_REQUEST is defined.
  2626. *
  2627. * @param int $post_id The ID in the database table of the post being published
  2628. */
  2629. function _publish_post_hook($post_id) {
  2630. global $wpdb;
  2631. if ( defined('XMLRPC_REQUEST') )
  2632. do_action('xmlrpc_publish_post', $post_id);
  2633. if ( defined('APP_REQUEST') )
  2634. do_action('app_publish_post', $post_id);
  2635. if ( defined('WP_IMPORTING') )
  2636. return;
  2637. $data = array( 'post_id' => $post_id, 'meta_value' => '1' );
  2638. if ( get_option('default_pingback_flag') )
  2639. $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_pingme' ) );
  2640. $wpdb->insert( $wpdb->postmeta, $data + array( 'meta_key' => '_encloseme' ) );
  2641. wp_schedule_single_event(time(), 'do_pings');
  2642. }
  2643. /**
  2644. * _save_post_hook() - Hook used to prevent page/post cache and rewrite rules from staying dirty
  2645. *
  2646. * Does two things. If the post is a page and has a template then it will update/add that
  2647. * template to the meta. For both pages and posts, it will clean the post cache to make sure
  2648. * that the cache updates to the changes done recently. For pages, the rewrite rules of
  2649. * WordPress are flushed to allow for any changes.
  2650. *
  2651. * The $post parameter, only uses 'post_type' property and 'page_template' property.
  2652. *
  2653. * @package WordPress
  2654. * @subpackage Post
  2655. * @since 2.3
  2656. *
  2657. * @uses $wp_rewrite Flushes Rewrite Rules.
  2658. *
  2659. * @param int $post_id The ID in the database table for the $post
  2660. * @param object $post Object type containing the post information
  2661. */
  2662. function _save_post_hook($post_id, $post) {
  2663. if ( $post->post_type == 'page' ) {
  2664. clean_page_cache($post_id);
  2665. global $wp_rewrite;
  2666. $wp_rewrite->flush_rules();
  2667. } else {
  2668. clean_post_cache($post_id);
  2669. }
  2670. }
  2671. //
  2672. // Private
  2673. //
  2674. function _get_post_ancestors(&$_post) {
  2675. global $wpdb;
  2676. if ( isset($_post->ancestors) )
  2677. return;
  2678. $_post->ancestors = array();
  2679. if ( empty($_post->post_parent) || $_post->ID == $_post->post_parent )
  2680. return;
  2681. $id = $_post->ancestors[] = $_post->post_parent;
  2682. while ( $ancestor = $wpdb->get_var( $wpdb->prepare("SELECT `post_parent` FROM $wpdb->posts WHERE ID = %d LIMIT 1", $id) ) ) {
  2683. if ( $id == $ancestor )
  2684. break;
  2685. $id = $_post->ancestors[] = $ancestor;
  2686. }
  2687. }
  2688. /* Post Revisions */
  2689. /**
  2690. * _wp_post_revision_fields() - determines which fields of posts are to be saved in revisions
  2691. *
  2692. * Does two things. If passed a post *array*, it will return a post array ready to be
  2693. * insterted into the posts table as a post revision.
  2694. * Otherwise, returns an array whose keys are the post fields to be saved for post revisions.
  2695. *
  2696. * @package WordPress
  2697. * @subpackage Post Revisions
  2698. * @since 2.6
  2699. *
  2700. * @param array $post optional a post array to be processed for insertion as a post revision
  2701. * @param bool $autosave optional Is the revision an autosave?
  2702. * @return array post array ready to be inserted as a post revision or array of fields that can be versioned
  2703. */
  2704. function _wp_post_revision_fields( $post = null, $autosave = false ) {
  2705. static $fields = false;
  2706. if ( !$fields ) {
  2707. // Allow these to be versioned
  2708. $fields = array(
  2709. 'post_title' => __( 'Title' ),
  2710. 'post_content' => __( 'Content' ),
  2711. 'post_excerpt' => __( 'Excerpt' ),
  2712. );
  2713. // Runs only once
  2714. $fields = apply_filters( '_wp_post_revision_fields', $fields );
  2715. // WP uses these internally either in versioning or elsewhere - they cannot be versioned
  2716. foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect )
  2717. unset( $fields[$protect] );
  2718. }
  2719. if ( !is_array($post) )
  2720. return $fields;
  2721. $return = array();
  2722. foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field )
  2723. $return[$field] = $post[$field];
  2724. $return['post_parent'] = $post['ID'];
  2725. $return['post_status'] = 'inherit';
  2726. $return['post_type'] = 'revision';
  2727. $return['post_name'] = $autosave ? "$post[ID]-autosave" : "$post[ID]-revision";
  2728. $return['post_date'] = $post['post_modified'];
  2729. $return['post_date_gmt'] = $post['post_modified_gmt'];
  2730. return $return;
  2731. }
  2732. /**
  2733. * wp_save_post_revision() - Saves an already existing post as a post revision. Typically used immediately prior to post updates.
  2734. *
  2735. * @package WordPress
  2736. * @subpackage Post Revisions
  2737. * @since 2.6
  2738. *
  2739. * @uses _wp_put_post_revision()
  2740. *
  2741. * @param int $post_id The ID of the post to save as a revision
  2742. * @return mixed null or 0 if error, new revision ID if success
  2743. */
  2744. function wp_save_post_revision( $post_id ) {
  2745. // We do autosaves manually with wp_create_post_autosave()
  2746. if ( @constant( 'DOING_AUTOSAVE' ) )
  2747. return;
  2748. // WP_POST_REVISIONS = 0, false
  2749. if ( !constant('WP_POST_REVISIONS') )
  2750. return;
  2751. if ( !$post = get_post( $post_id, ARRAY_A ) )
  2752. return;
  2753. if ( !in_array( $post['post_type'], array( 'post', 'page' ) ) )
  2754. return;
  2755. $return = _wp_put_post_revision( $post );
  2756. // WP_POST_REVISIONS = true (default), -1
  2757. if ( !is_numeric( WP_POST_REVISIONS ) || WP_POST_REVISIONS < 0 )
  2758. return $return;
  2759. // all revisions and (possibly) one autosave
  2760. $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
  2761. // WP_POST_REVISIONS = (int) (# of autasaves to save)
  2762. $delete = count($revisions) - WP_POST_REVISIONS;
  2763. if ( $delete < 1 )
  2764. return $return;
  2765. $revisions = array_slice( $revisions, 0, $delete );
  2766. for ( $i = 0; isset($revisions[$i]); $i++ ) {
  2767. if ( false !== strpos( $revisions[$i]->post_name, 'autosave' ) )
  2768. continue;
  2769. wp_delete_post_revision( $revisions[$i]->ID );
  2770. }
  2771. return $return;
  2772. }
  2773. /**
  2774. * wp_get_post_autosave() - returns the autosaved data of the specified post.
  2775. *
  2776. * Returns a post object containing the information that was autosaved for the specified post.
  2777. *
  2778. * @package WordPress
  2779. * @subpackage Post Revisions
  2780. * @since 2.6
  2781. *
  2782. * @param int $post_id The post ID
  2783. * @return object|bool the autosaved data or false on failure or when no autosave exists
  2784. */
  2785. function wp_get_post_autosave( $post_id ) {
  2786. global $wpdb;
  2787. if ( !$post = get_post( $post_id ) )
  2788. return false;
  2789. $q = array(
  2790. 'name' => "{$post->ID}-autosave",
  2791. 'post_parent' => $post->ID,
  2792. 'post_type' => 'revision',
  2793. 'post_status' => 'inherit'
  2794. );
  2795. // Use WP_Query so that the result gets cached
  2796. $autosave_query = new WP_Query;
  2797. add_action( 'parse_query', '_wp_get_post_autosave_hack' );
  2798. $autosave = $autosave_query->query( $q );
  2799. remove_action( 'parse_query', '_wp_get_post_autosave_hack' );
  2800. if ( $autosave && is_array($autosave) && is_object($autosave[0]) )
  2801. return $autosave[0];
  2802. return false;
  2803. }
  2804. // Internally used to hack WP_Query into submission
  2805. function _wp_get_post_autosave_hack( $query ) {
  2806. $query->is_single = false;
  2807. }
  2808. /**
  2809. * wp_is_post_revision() - Determines if the specified post is a revision.
  2810. *
  2811. * @package WordPress
  2812. * @subpackage Post Revisions
  2813. * @since 2.6
  2814. *
  2815. * @param int|object $post post ID or post object
  2816. * @return bool|int false if not a revision, ID of revision's parent otherwise
  2817. */
  2818. function wp_is_post_revision( $post ) {
  2819. if ( !$post = wp_get_post_revision( $post ) )
  2820. return false;
  2821. return (int) $post->post_parent;
  2822. }
  2823. /**
  2824. * wp_is_post_autosave() - Determines if the specified post is an autosave.
  2825. *
  2826. * @package WordPress
  2827. * @subpackage Post Revisions
  2828. * @since 2.6
  2829. *
  2830. * @param int|object $post post ID or post object
  2831. * @return bool|int false if not a revision, ID of autosave's parent otherwise
  2832. */
  2833. function wp_is_post_autosave( $post ) {
  2834. if ( !$post = wp_get_post_revision( $post ) )
  2835. return false;
  2836. if ( "{$post->post_parent}-autosave" !== $post->post_name )
  2837. return false;
  2838. return (int) $post->post_parent;
  2839. }
  2840. /**
  2841. * _wp_put_post_revision() - Inserts post data into the posts table as a post revision
  2842. *
  2843. * @package WordPress
  2844. * @subpackage Post Revisions
  2845. * @since 2.6
  2846. *
  2847. * @uses wp_insert_post()
  2848. *
  2849. * @param int|object|array $post post ID, post object OR post array
  2850. * @param bool $autosave optional Is the revision an autosave?
  2851. * @return mixed null or 0 if error, new revision ID if success
  2852. */
  2853. function _wp_put_post_revision( $post = null, $autosave = false ) {
  2854. if ( is_object($post) )
  2855. $post = get_object_vars( $post );
  2856. elseif ( !is_array($post) )
  2857. $post = get_post($post, ARRAY_A);
  2858. if ( !$post || empty($post['ID']) )
  2859. return;
  2860. if ( isset($post['post_type']) && 'revision' == $post_post['type'] )
  2861. return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
  2862. $post = _wp_post_revision_fields( $post, $autosave );
  2863. $revision_id = wp_insert_post( $post );
  2864. if ( is_wp_error($revision_id) )
  2865. return $revision_id;
  2866. if ( $revision_id )
  2867. do_action( '_wp_put_post_revision', $revision_id );
  2868. return $revision_id;
  2869. }
  2870. /**
  2871. * wp_get_post_revision() - Gets a post revision
  2872. *
  2873. * @package WordPress
  2874. * @subpackage Post Revisions
  2875. * @since 2.6
  2876. *
  2877. * @uses get_post()
  2878. *
  2879. * @param int|object $post post ID or post object
  2880. * @param $output optional OBJECT, ARRAY_A, or ARRAY_N
  2881. * @param string $filter optional sanitation filter. @see sanitize_post()
  2882. * @return mixed null if error or post object if success
  2883. */
  2884. function &wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') {
  2885. $null = null;
  2886. if ( !$revision = get_post( $post, OBJECT, $filter ) )
  2887. return $revision;
  2888. if ( 'revision' !== $revision->post_type )
  2889. return $null;
  2890. if ( $output == OBJECT ) {
  2891. return $revision;
  2892. } elseif ( $output == ARRAY_A ) {
  2893. $_revision = get_object_vars($revision);
  2894. return $_revision;
  2895. } elseif ( $output == ARRAY_N ) {
  2896. $_revision = array_values(get_object_vars($revision));
  2897. return $_revision;
  2898. }
  2899. return $revision;
  2900. }
  2901. /**
  2902. * wp_restore_post_revision() - Restores a post to the specified revision
  2903. *
  2904. * Can restore a past using all fields of the post revision, or only selected fields.
  2905. *
  2906. * @package WordPress
  2907. * @subpackage Post Revisions
  2908. * @since 2.6
  2909. *
  2910. * @uses wp_get_post_revision()
  2911. * @uses wp_update_post()
  2912. *
  2913. * @param int|object $revision_id revision ID or revision object
  2914. * @param array $fields optional What fields to restore from. Defaults to all.
  2915. * @return mixed null if error, false if no fields to restore, (int) post ID if success
  2916. */
  2917. function wp_restore_post_revision( $revision_id, $fields = null ) {
  2918. if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) )
  2919. return $revision;
  2920. if ( !is_array( $fields ) )
  2921. $fields = array_keys( _wp_post_revision_fields() );
  2922. $update = array();
  2923. foreach( array_intersect( array_keys( $revision ), $fields ) as $field )
  2924. $update[$field] = $revision[$field];
  2925. if ( !$update )
  2926. return false;
  2927. $update['ID'] = $revision['post_parent'];
  2928. $post_id = wp_update_post( $update );
  2929. if ( is_wp_error( $post_id ) )
  2930. return $post_id;
  2931. if ( $post_id )
  2932. do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] );
  2933. return $post_id;
  2934. }
  2935. /**
  2936. * wp_delete_post_revision() - Deletes a revision.
  2937. *
  2938. * Deletes the row from the posts table corresponding to the specified revision
  2939. *
  2940. * @package WordPress
  2941. * @subpackage Post Revisions
  2942. * @since 2.6
  2943. *
  2944. * @uses wp_get_post_revision()
  2945. * @uses wp_delete_post()
  2946. *
  2947. * @param int|object $revision_id revision ID or revision object
  2948. * @param array $fields optional What fields to restore from. Defaults to all.
  2949. * @return mixed null if error, false if no fields to restore, (int) post ID if success
  2950. */
  2951. function wp_delete_post_revision( $revision_id ) {
  2952. if ( !$revision = wp_get_post_revision( $revision_id ) )
  2953. return $revision;
  2954. $delete = wp_delete_post( $revision->ID );
  2955. if ( is_wp_error( $delete ) )
  2956. return $delete;
  2957. if ( $delete )
  2958. do_action( 'wp_delete_post_revision', $revision->ID, $revision );
  2959. return $delete;
  2960. }
  2961. /**
  2962. * wp_get_post_revisions() - Returns all revisions of specified post
  2963. *
  2964. * @package WordPress
  2965. * @subpackage Post Revisions
  2966. * @since 2.6
  2967. *
  2968. * @uses get_children()
  2969. *
  2970. * @param int|object $post_id post ID or post object
  2971. * @return array empty if no revisions
  2972. */
  2973. function wp_get_post_revisions( $post_id = 0, $args = null ) {
  2974. if ( !constant('WP_POST_REVISIONS') )
  2975. return array();
  2976. if ( ( !$post = get_post( $post_id ) ) || empty( $post->ID ) )
  2977. return array();
  2978. $defaults = array( 'order' => 'DESC', 'orderby' => 'date' );
  2979. $args = wp_parse_args( $args, $defaults );
  2980. $args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) );
  2981. if ( !$revisions = get_children( $args ) )
  2982. return array();
  2983. return $revisions;
  2984. }