PageRenderTime 63ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-admin/wp-admin/includes/post.php

https://bitbucket.org/crypticrod/sr_wp_code
PHP | 1864 lines | 1180 code | 307 blank | 377 comment | 348 complexity | 6cbdfe08b3d0534c711f20ae41d7758c MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.1, GPL-3.0, LGPL-2.0, AGPL-3.0

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

  1. <?php
  2. /**
  3. * WordPress Post Administration API.
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. */
  8. /**
  9. * Rename $_POST data from form names to DB post columns.
  10. *
  11. * Manipulates $_POST directly.
  12. *
  13. * @package WordPress
  14. * @since 2.6.0
  15. *
  16. * @param bool $update Are we updating a pre-existing post?
  17. * @param array $post_data Array of post data. Defaults to the contents of $_POST.
  18. * @return object|bool WP_Error on failure, true on success.
  19. */
  20. function _wp_translate_postdata( $update = false, $post_data = null ) {
  21. if ( empty($post_data) )
  22. $post_data = &$_POST;
  23. if ( $update )
  24. $post_data['ID'] = (int) $post_data['post_ID'];
  25. if ( isset( $post_data['content'] ) )
  26. $post_data['post_content'] = $post_data['content'];
  27. if ( isset( $post_data['excerpt'] ) )
  28. $post_data['post_excerpt'] = $post_data['excerpt'];
  29. if ( isset( $post_data['parent_id'] ) )
  30. $post_data['post_parent'] = (int) $post_data['parent_id'];
  31. if ( isset($post_data['trackback_url']) )
  32. $post_data['to_ping'] = $post_data['trackback_url'];
  33. if ( !isset($post_data['user_ID']) )
  34. $post_data['user_ID'] = $GLOBALS['user_ID'];
  35. if (!empty ( $post_data['post_author_override'] ) ) {
  36. $post_data['post_author'] = (int) $post_data['post_author_override'];
  37. } else {
  38. if (!empty ( $post_data['post_author'] ) ) {
  39. $post_data['post_author'] = (int) $post_data['post_author'];
  40. } else {
  41. $post_data['post_author'] = (int) $post_data['user_ID'];
  42. }
  43. }
  44. $ptype = get_post_type_object( $post_data['post_type'] );
  45. if ( isset($post_data['user_ID']) && ($post_data['post_author'] != $post_data['user_ID']) ) {
  46. if ( !current_user_can( $ptype->cap->edit_others_posts ) ) {
  47. if ( 'page' == $post_data['post_type'] ) {
  48. return new WP_Error( 'edit_others_pages', $update ?
  49. __( 'You are not allowed to edit pages as this user.' ) :
  50. __( 'You are not allowed to create pages as this user.' )
  51. );
  52. } else {
  53. return new WP_Error( 'edit_others_posts', $update ?
  54. __( 'You are not allowed to edit posts as this user.' ) :
  55. __( 'You are not allowed to post as this user.' )
  56. );
  57. }
  58. }
  59. }
  60. // What to do based on which button they pressed
  61. if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
  62. $post_data['post_status'] = 'draft';
  63. if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
  64. $post_data['post_status'] = 'private';
  65. if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
  66. $post_data['post_status'] = 'publish';
  67. if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
  68. $post_data['post_status'] = 'draft';
  69. if ( isset($post_data['pending']) && '' != $post_data['pending'] )
  70. $post_data['post_status'] = 'pending';
  71. if ( isset( $post_data['ID'] ) )
  72. $post_id = $post_data['ID'];
  73. else
  74. $post_id = false;
  75. $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
  76. // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
  77. // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
  78. if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
  79. if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
  80. $post_data['post_status'] = 'pending';
  81. if ( ! isset($post_data['post_status']) )
  82. $post_data['post_status'] = $previous_status;
  83. if (!isset( $post_data['comment_status'] ))
  84. $post_data['comment_status'] = 'closed';
  85. if (!isset( $post_data['ping_status'] ))
  86. $post_data['ping_status'] = 'closed';
  87. foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
  88. if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
  89. $post_data['edit_date'] = '1';
  90. break;
  91. }
  92. }
  93. if ( !empty( $post_data['edit_date'] ) ) {
  94. $aa = $post_data['aa'];
  95. $mm = $post_data['mm'];
  96. $jj = $post_data['jj'];
  97. $hh = $post_data['hh'];
  98. $mn = $post_data['mn'];
  99. $ss = $post_data['ss'];
  100. $aa = ($aa <= 0 ) ? date('Y') : $aa;
  101. $mm = ($mm <= 0 ) ? date('n') : $mm;
  102. $jj = ($jj > 31 ) ? 31 : $jj;
  103. $jj = ($jj <= 0 ) ? date('j') : $jj;
  104. $hh = ($hh > 23 ) ? $hh -24 : $hh;
  105. $mn = ($mn > 59 ) ? $mn -60 : $mn;
  106. $ss = ($ss > 59 ) ? $ss -60 : $ss;
  107. $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
  108. $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
  109. }
  110. return $post_data;
  111. }
  112. /**
  113. * Update an existing post with values provided in $_POST.
  114. *
  115. * @since 1.5.0
  116. *
  117. * @param array $post_data Optional.
  118. * @return int Post ID.
  119. */
  120. function edit_post( $post_data = null ) {
  121. if ( empty($post_data) )
  122. $post_data = &$_POST;
  123. // Clear out any data in internal vars.
  124. unset( $post_data['filter'] );
  125. $post_ID = (int) $post_data['post_ID'];
  126. $post = get_post( $post_ID );
  127. $post_data['post_type'] = $post->post_type;
  128. $post_data['post_mime_type'] = $post->post_mime_type;
  129. $ptype = get_post_type_object($post_data['post_type']);
  130. if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
  131. if ( 'page' == $post_data['post_type'] )
  132. wp_die( __('You are not allowed to edit this page.' ));
  133. else
  134. wp_die( __('You are not allowed to edit this post.' ));
  135. }
  136. // Autosave shouldn't save too soon after a real save
  137. if ( 'autosave' == $post_data['action'] ) {
  138. $post =& get_post( $post_ID );
  139. $now = time();
  140. $then = strtotime($post->post_date_gmt . ' +0000');
  141. $delta = AUTOSAVE_INTERVAL / 2;
  142. if ( ($now - $then) < $delta )
  143. return $post_ID;
  144. }
  145. $post_data = _wp_translate_postdata( true, $post_data );
  146. if ( is_wp_error($post_data) )
  147. wp_die( $post_data->get_error_message() );
  148. if ( 'autosave' != $post_data['action'] && 'auto-draft' == $post_data['post_status'] )
  149. $post_data['post_status'] = 'draft';
  150. if ( isset($post_data['visibility']) ) {
  151. switch ( $post_data['visibility'] ) {
  152. case 'public' :
  153. $post_data['post_password'] = '';
  154. break;
  155. case 'password' :
  156. unset( $post_data['sticky'] );
  157. break;
  158. case 'private' :
  159. $post_data['post_status'] = 'private';
  160. $post_data['post_password'] = '';
  161. unset( $post_data['sticky'] );
  162. break;
  163. }
  164. }
  165. // Post Formats
  166. if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) {
  167. $formats = get_theme_support( 'post-formats' );
  168. if ( is_array( $formats ) ) {
  169. $formats = $formats[0];
  170. if ( in_array( $post_data['post_format'], $formats ) ) {
  171. set_post_format( $post_ID, $post_data['post_format'] );
  172. } elseif ( '0' == $post_data['post_format'] ) {
  173. set_post_format( $post_ID, false );
  174. }
  175. }
  176. }
  177. // Meta Stuff
  178. if ( isset($post_data['meta']) && $post_data['meta'] ) {
  179. foreach ( $post_data['meta'] as $key => $value ) {
  180. if ( !$meta = get_post_meta_by_id( $key ) )
  181. continue;
  182. if ( $meta->post_id != $post_ID )
  183. continue;
  184. if ( is_protected_meta( $value['key'] ) )
  185. continue;
  186. update_meta( $key, $value['key'], $value['value'] );
  187. }
  188. }
  189. if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
  190. foreach ( $post_data['deletemeta'] as $key => $value ) {
  191. if ( !$meta = get_post_meta_by_id( $key ) )
  192. continue;
  193. if ( $meta->post_id != $post_ID )
  194. continue;
  195. if ( is_protected_meta( $meta->meta_key ) )
  196. continue;
  197. delete_meta( $key );
  198. }
  199. }
  200. add_meta( $post_ID );
  201. update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
  202. wp_update_post( $post_data );
  203. // Reunite any orphaned attachments with their parent
  204. if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
  205. $draft_ids = array();
  206. if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
  207. _relocate_children( $draft_temp_id, $post_ID );
  208. // Now that we have an ID we can fix any attachment anchor hrefs
  209. _fix_attachment_links( $post_ID );
  210. wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
  211. if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
  212. if ( ! empty( $post_data['sticky'] ) )
  213. stick_post( $post_ID );
  214. else
  215. unstick_post( $post_ID );
  216. }
  217. return $post_ID;
  218. }
  219. /**
  220. * Process the post data for the bulk editing of posts.
  221. *
  222. * Updates all bulk edited posts/pages, adding (but not removing) tags and
  223. * categories. Skips pages when they would be their own parent or child.
  224. *
  225. * @since 2.7.0
  226. *
  227. * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
  228. * @return array
  229. */
  230. function bulk_edit_posts( $post_data = null ) {
  231. global $wpdb;
  232. if ( empty($post_data) )
  233. $post_data = &$_POST;
  234. if ( isset($post_data['post_type']) )
  235. $ptype = get_post_type_object($post_data['post_type']);
  236. else
  237. $ptype = get_post_type_object('post');
  238. if ( !current_user_can( $ptype->cap->edit_posts ) ) {
  239. if ( 'page' == $ptype->name )
  240. wp_die( __('You are not allowed to edit pages.'));
  241. else
  242. wp_die( __('You are not allowed to edit posts.'));
  243. }
  244. if ( -1 == $post_data['_status'] ) {
  245. $post_data['post_status'] = null;
  246. unset($post_data['post_status']);
  247. } else {
  248. $post_data['post_status'] = $post_data['_status'];
  249. }
  250. unset($post_data['_status']);
  251. $post_IDs = array_map( 'intval', (array) $post_data['post'] );
  252. $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
  253. foreach ( $reset as $field ) {
  254. if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
  255. unset($post_data[$field]);
  256. }
  257. if ( isset($post_data['post_category']) ) {
  258. if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
  259. $new_cats = array_map( 'absint', $post_data['post_category'] );
  260. else
  261. unset($post_data['post_category']);
  262. }
  263. $tax_input = array();
  264. if ( isset($post_data['tax_input'])) {
  265. foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
  266. if ( empty($terms) )
  267. continue;
  268. if ( is_taxonomy_hierarchical( $tax_name ) )
  269. $tax_input[$tax_name] = array_map( 'absint', $terms );
  270. else {
  271. $tax_input[$tax_name] = preg_replace( '/\s*,\s*/', ',', rtrim( trim($terms), ' ,' ) );
  272. $tax_input[$tax_name] = explode(',', $tax_input[$tax_name]);
  273. }
  274. }
  275. }
  276. if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
  277. $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
  278. $children = array();
  279. for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
  280. $children[] = $parent;
  281. foreach ( $pages as $page ) {
  282. if ( $page->ID == $parent ) {
  283. $parent = $page->post_parent;
  284. break;
  285. }
  286. }
  287. }
  288. }
  289. $updated = $skipped = $locked = array();
  290. foreach ( $post_IDs as $post_ID ) {
  291. $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
  292. if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
  293. $skipped[] = $post_ID;
  294. continue;
  295. }
  296. if ( wp_check_post_lock( $post_ID ) ) {
  297. $locked[] = $post_ID;
  298. continue;
  299. }
  300. $post = get_post( $post_ID );
  301. $tax_names = get_object_taxonomies( $post );
  302. foreach ( $tax_names as $tax_name ) {
  303. $taxonomy_obj = get_taxonomy($tax_name);
  304. if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
  305. $new_terms = $tax_input[$tax_name];
  306. else
  307. $new_terms = array();
  308. if ( $taxonomy_obj->hierarchical )
  309. $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
  310. else
  311. $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
  312. $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
  313. }
  314. if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
  315. $cats = (array) wp_get_post_categories($post_ID);
  316. $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
  317. unset( $post_data['tax_input']['category'] );
  318. }
  319. $post_data['post_mime_type'] = $post->post_mime_type;
  320. $post_data['guid'] = $post->guid;
  321. $post_data['ID'] = $post_ID;
  322. $updated[] = wp_update_post( $post_data );
  323. if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
  324. if ( 'sticky' == $post_data['sticky'] )
  325. stick_post( $post_ID );
  326. else
  327. unstick_post( $post_ID );
  328. }
  329. }
  330. return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
  331. }
  332. /**
  333. * Default post information to use when populating the "Write Post" form.
  334. *
  335. * @since 2.0.0
  336. *
  337. * @param string $post_type A post type string, defaults to 'post'.
  338. * @return object stdClass object containing all the default post data as attributes
  339. */
  340. function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
  341. global $wpdb;
  342. $post_title = '';
  343. if ( !empty( $_REQUEST['post_title'] ) )
  344. $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
  345. $post_content = '';
  346. if ( !empty( $_REQUEST['content'] ) )
  347. $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
  348. $post_excerpt = '';
  349. if ( !empty( $_REQUEST['excerpt'] ) )
  350. $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
  351. if ( $create_in_db ) {
  352. // Cleanup old auto-drafts more than 7 days old
  353. $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
  354. foreach ( (array) $old_posts as $delete )
  355. wp_delete_post( $delete, true ); // Force delete
  356. $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
  357. $post = get_post( $post_id );
  358. if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
  359. set_post_format( $post, get_option( 'default_post_format' ) );
  360. } else {
  361. $post->ID = 0;
  362. $post->post_author = '';
  363. $post->post_date = '';
  364. $post->post_date_gmt = '';
  365. $post->post_password = '';
  366. $post->post_type = $post_type;
  367. $post->post_status = 'draft';
  368. $post->to_ping = '';
  369. $post->pinged = '';
  370. $post->comment_status = get_option( 'default_comment_status' );
  371. $post->ping_status = get_option( 'default_ping_status' );
  372. $post->post_pingback = get_option( 'default_pingback_flag' );
  373. $post->post_category = get_option( 'default_category' );
  374. $post->page_template = 'default';
  375. $post->post_parent = 0;
  376. $post->menu_order = 0;
  377. }
  378. $post->post_content = apply_filters( 'default_content', $post_content, $post );
  379. $post->post_title = apply_filters( 'default_title', $post_title, $post );
  380. $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
  381. $post->post_name = '';
  382. return $post;
  383. }
  384. /**
  385. * Get the default page information to use.
  386. *
  387. * @since 2.5.0
  388. *
  389. * @return object stdClass object containing all the default post data as attributes
  390. */
  391. function get_default_page_to_edit() {
  392. $page = get_default_post_to_edit();
  393. $page->post_type = 'page';
  394. return $page;
  395. }
  396. /**
  397. * Get an existing post and format it for editing.
  398. *
  399. * @since 2.0.0
  400. *
  401. * @param unknown_type $id
  402. * @return unknown
  403. */
  404. function get_post_to_edit( $id ) {
  405. $post = get_post( $id, OBJECT, 'edit' );
  406. if ( $post->post_type == 'page' )
  407. $post->page_template = get_post_meta( $id, '_wp_page_template', true );
  408. return $post;
  409. }
  410. /**
  411. * Determine if a post exists based on title, content, and date
  412. *
  413. * @since 2.0.0
  414. *
  415. * @param string $title Post title
  416. * @param string $content Optional post content
  417. * @param string $date Optional post date
  418. * @return int Post ID if post exists, 0 otherwise.
  419. */
  420. function post_exists($title, $content = '', $date = '') {
  421. global $wpdb;
  422. $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
  423. $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
  424. $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
  425. $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
  426. $args = array();
  427. if ( !empty ( $date ) ) {
  428. $query .= ' AND post_date = %s';
  429. $args[] = $post_date;
  430. }
  431. if ( !empty ( $title ) ) {
  432. $query .= ' AND post_title = %s';
  433. $args[] = $post_title;
  434. }
  435. if ( !empty ( $content ) ) {
  436. $query .= 'AND post_content = %s';
  437. $args[] = $post_content;
  438. }
  439. if ( !empty ( $args ) )
  440. return $wpdb->get_var( $wpdb->prepare($query, $args) );
  441. return 0;
  442. }
  443. /**
  444. * Creates a new post from the "Write Post" form using $_POST information.
  445. *
  446. * @since 2.1.0
  447. *
  448. * @return unknown
  449. */
  450. function wp_write_post() {
  451. global $user_ID;
  452. if ( isset($_POST['post_type']) )
  453. $ptype = get_post_type_object($_POST['post_type']);
  454. else
  455. $ptype = get_post_type_object('post');
  456. if ( !current_user_can( $ptype->cap->edit_posts ) ) {
  457. if ( 'page' == $ptype->name )
  458. return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
  459. else
  460. return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
  461. }
  462. $_POST['post_mime_type'] = '';
  463. // Clear out any data in internal vars.
  464. unset( $_POST['filter'] );
  465. // Check for autosave collisions
  466. // Does this need to be updated? ~ Mark
  467. $temp_id = false;
  468. if ( isset($_POST['temp_ID']) ) {
  469. $temp_id = (int) $_POST['temp_ID'];
  470. if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
  471. $draft_ids = array();
  472. foreach ( $draft_ids as $temp => $real )
  473. if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
  474. unset($draft_ids[$temp]);
  475. if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
  476. $_POST['post_ID'] = $draft_ids[$temp_id];
  477. unset($_POST['temp_ID']);
  478. update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
  479. return edit_post();
  480. }
  481. }
  482. // Edit don't write if we have a post id.
  483. if ( isset( $_POST['ID'] ) ) {
  484. $_POST['post_ID'] = $_POST['ID'];
  485. unset ( $_POST['ID'] );
  486. }
  487. if ( isset( $_POST['post_ID'] ) ) {
  488. return edit_post();
  489. }
  490. $translated = _wp_translate_postdata( false );
  491. if ( is_wp_error($translated) )
  492. return $translated;
  493. if ( isset($_POST['visibility']) ) {
  494. switch ( $_POST['visibility'] ) {
  495. case 'public' :
  496. $_POST['post_password'] = '';
  497. break;
  498. case 'password' :
  499. unset( $_POST['sticky'] );
  500. break;
  501. case 'private' :
  502. $_POST['post_status'] = 'private';
  503. $_POST['post_password'] = '';
  504. unset( $_POST['sticky'] );
  505. break;
  506. }
  507. }
  508. // Create the post.
  509. $post_ID = wp_insert_post( $_POST );
  510. if ( is_wp_error( $post_ID ) )
  511. return $post_ID;
  512. if ( empty($post_ID) )
  513. return 0;
  514. add_meta( $post_ID );
  515. add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
  516. // Reunite any orphaned attachments with their parent
  517. // Does this need to be udpated? ~ Mark
  518. if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
  519. $draft_ids = array();
  520. if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
  521. _relocate_children( $draft_temp_id, $post_ID );
  522. if ( $temp_id && $temp_id != $draft_temp_id )
  523. _relocate_children( $temp_id, $post_ID );
  524. // Update autosave collision detection
  525. if ( $temp_id ) {
  526. $draft_ids[$temp_id] = $post_ID;
  527. update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
  528. }
  529. // Now that we have an ID we can fix any attachment anchor hrefs
  530. _fix_attachment_links( $post_ID );
  531. wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
  532. return $post_ID;
  533. }
  534. /**
  535. * Calls wp_write_post() and handles the errors.
  536. *
  537. * @since 2.0.0
  538. *
  539. * @return unknown
  540. */
  541. function write_post() {
  542. $result = wp_write_post();
  543. if ( is_wp_error( $result ) )
  544. wp_die( $result->get_error_message() );
  545. else
  546. return $result;
  547. }
  548. //
  549. // Post Meta
  550. //
  551. /**
  552. * {@internal Missing Short Description}}
  553. *
  554. * @since 1.2.0
  555. *
  556. * @param unknown_type $post_ID
  557. * @return unknown
  558. */
  559. function add_meta( $post_ID ) {
  560. global $wpdb;
  561. $post_ID = (int) $post_ID;
  562. $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
  563. $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
  564. $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes_deep( $_POST['metavalue'] ) ) : '';
  565. if ( is_string($metavalue) )
  566. $metavalue = trim( $metavalue );
  567. if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
  568. // We have a key/value pair. If both the select and the
  569. // input for the key have data, the input takes precedence:
  570. if ('#NONE#' != $metakeyselect)
  571. $metakey = $metakeyselect;
  572. if ( $metakeyinput)
  573. $metakey = $metakeyinput; // default
  574. if ( is_protected_meta( $metakey ) )
  575. return false;
  576. wp_cache_delete($post_ID, 'post_meta');
  577. $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) );
  578. $meta_id = $wpdb->insert_id;
  579. do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue );
  580. return $meta_id;
  581. }
  582. return false;
  583. } // add_meta
  584. /**
  585. * {@internal Missing Short Description}}
  586. *
  587. * @since 1.2.0
  588. *
  589. * @param unknown_type $mid
  590. * @return unknown
  591. */
  592. function delete_meta( $mid ) {
  593. global $wpdb;
  594. $mid = (int) $mid;
  595. $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
  596. do_action( 'delete_postmeta', $mid );
  597. wp_cache_delete($post_id, 'post_meta');
  598. $rval = $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
  599. do_action( 'deleted_postmeta', $mid );
  600. return $rval;
  601. }
  602. /**
  603. * Get a list of previously defined keys.
  604. *
  605. * @since 1.2.0
  606. *
  607. * @return unknown
  608. */
  609. function get_meta_keys() {
  610. global $wpdb;
  611. $keys = $wpdb->get_col( "
  612. SELECT meta_key
  613. FROM $wpdb->postmeta
  614. GROUP BY meta_key
  615. ORDER BY meta_key" );
  616. return $keys;
  617. }
  618. /**
  619. * {@internal Missing Short Description}}
  620. *
  621. * @since 2.1.0
  622. *
  623. * @param unknown_type $mid
  624. * @return unknown
  625. */
  626. function get_post_meta_by_id( $mid ) {
  627. global $wpdb;
  628. $mid = (int) $mid;
  629. $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
  630. if ( empty($meta) )
  631. return false;
  632. if ( is_serialized_string( $meta->meta_value ) )
  633. $meta->meta_value = maybe_unserialize( $meta->meta_value );
  634. return $meta;
  635. }
  636. /**
  637. * {@internal Missing Short Description}}
  638. *
  639. * Some postmeta stuff.
  640. *
  641. * @since 1.2.0
  642. *
  643. * @param unknown_type $postid
  644. * @return unknown
  645. */
  646. function has_meta( $postid ) {
  647. global $wpdb;
  648. return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
  649. FROM $wpdb->postmeta WHERE post_id = %d
  650. ORDER BY meta_key,meta_id", $postid), ARRAY_A );
  651. }
  652. /**
  653. * {@internal Missing Short Description}}
  654. *
  655. * @since 1.2.0
  656. *
  657. * @param unknown_type $meta_id
  658. * @param unknown_type $meta_key Expect Slashed
  659. * @param unknown_type $meta_value Expect Slashed
  660. * @return unknown
  661. */
  662. function update_meta( $meta_id, $meta_key, $meta_value ) {
  663. global $wpdb;
  664. $meta_key = stripslashes($meta_key);
  665. if ( is_protected_meta( $meta_key ) )
  666. return false;
  667. if ( '' === trim( $meta_value ) )
  668. return false;
  669. $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
  670. $meta_value = maybe_serialize( stripslashes_deep( $meta_value ) );
  671. $meta_id = (int) $meta_id;
  672. $data = compact( 'meta_key', 'meta_value' );
  673. $where = compact( 'meta_id' );
  674. do_action( 'update_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
  675. $rval = $wpdb->update( $wpdb->postmeta, $data, $where );
  676. wp_cache_delete($post_id, 'post_meta');
  677. do_action( 'updated_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
  678. return $rval;
  679. }
  680. //
  681. // Private
  682. //
  683. /**
  684. * Replace hrefs of attachment anchors with up-to-date permalinks.
  685. *
  686. * @since 2.3.0
  687. * @access private
  688. *
  689. * @param unknown_type $post_ID
  690. * @return unknown
  691. */
  692. function _fix_attachment_links( $post_ID ) {
  693. global $_fix_attachment_link_id;
  694. $post = & get_post( $post_ID, ARRAY_A );
  695. $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
  696. // See if we have any rel="attachment" links
  697. if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
  698. return;
  699. $i = 0;
  700. $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
  701. foreach ( $anchor_matches[0] as $anchor ) {
  702. if ( 0 == preg_match( $search, $anchor, $id_matches ) )
  703. continue;
  704. $id = (int) $id_matches[3];
  705. // While we have the attachment ID, let's adopt any orphans.
  706. $attachment = & get_post( $id, ARRAY_A );
  707. if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
  708. $attachment['post_parent'] = $post_ID;
  709. // Escape data pulled from DB.
  710. $attachment = add_magic_quotes( $attachment );
  711. wp_update_post( $attachment );
  712. }
  713. $post_search[$i] = $anchor;
  714. $_fix_attachment_link_id = $id;
  715. $post_replace[$i] = preg_replace_callback( "#href=(\"|')[^'\"]*\\1#", '_fix_attachment_links_replace_cb', $anchor );
  716. ++$i;
  717. }
  718. $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
  719. // Escape data pulled from DB.
  720. $post = add_magic_quotes( $post);
  721. return wp_update_post( $post);
  722. }
  723. function _fix_attachment_links_replace_cb($match) {
  724. global $_fix_attachment_link_id;
  725. return stripslashes( 'href='.$match[1] ).get_attachment_link( $_fix_attachment_link_id ).stripslashes( $match[1] );
  726. }
  727. /**
  728. * Move child posts to a new parent.
  729. *
  730. * @since 2.3.0
  731. * @access private
  732. *
  733. * @param unknown_type $old_ID
  734. * @param unknown_type $new_ID
  735. * @return unknown
  736. */
  737. function _relocate_children( $old_ID, $new_ID ) {
  738. global $wpdb;
  739. $old_ID = (int) $old_ID;
  740. $new_ID = (int) $new_ID;
  741. $children = $wpdb->get_col( $wpdb->prepare("
  742. SELECT post_id
  743. FROM $wpdb->postmeta
  744. WHERE meta_key = '_wp_attachment_temp_parent'
  745. AND meta_value = %d", $old_ID) );
  746. foreach ( $children as $child_id ) {
  747. $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
  748. delete_post_meta($child_id, '_wp_attachment_temp_parent');
  749. }
  750. }
  751. /**
  752. * Get all the possible statuses for a post_type
  753. *
  754. * @since 2.5.0
  755. *
  756. * @param string $type The post_type you want the statuses for
  757. * @return array As array of all the statuses for the supplied post type
  758. */
  759. function get_available_post_statuses($type = 'post') {
  760. $stati = wp_count_posts($type);
  761. return array_keys(get_object_vars($stati));
  762. }
  763. /**
  764. * Run the wp query to fetch the posts for listing on the edit posts page
  765. *
  766. * @since 2.5.0
  767. *
  768. * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
  769. * @return array
  770. */
  771. function wp_edit_posts_query( $q = false ) {
  772. if ( false === $q )
  773. $q = $_GET;
  774. $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
  775. $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
  776. $post_stati = get_post_stati();
  777. if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
  778. $post_type = $q['post_type'];
  779. else
  780. $post_type = 'post';
  781. $avail_post_stati = get_available_post_statuses($post_type);
  782. if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
  783. $post_status = $q['post_status'];
  784. $perm = 'readable';
  785. }
  786. if ( isset($q['orderby']) )
  787. $orderby = $q['orderby'];
  788. elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
  789. $orderby = 'modified';
  790. if ( isset($q['order']) )
  791. $order = $q['order'];
  792. elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
  793. $order = 'ASC';
  794. $per_page = 'edit_' . $post_type . '_per_page';
  795. $posts_per_page = (int) get_user_option( $per_page );
  796. if ( empty( $posts_per_page ) || $posts_per_page < 1 )
  797. $posts_per_page = 20;
  798. $posts_per_page = apply_filters( $per_page, $posts_per_page );
  799. $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
  800. $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
  801. // Hierarchical types require special args.
  802. if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
  803. $query['orderby'] = 'menu_order title';
  804. $query['order'] = 'asc';
  805. $query['posts_per_page'] = -1;
  806. $query['posts_per_archive_page'] = -1;
  807. }
  808. if ( ! empty( $q['show_sticky'] ) )
  809. $query['post__in'] = (array) get_option( 'sticky_posts' );
  810. wp( $query );
  811. return $avail_post_stati;
  812. }
  813. /**
  814. * Get default post mime types
  815. *
  816. * @since 2.9.0
  817. *
  818. * @return array
  819. */
  820. function get_post_mime_types() {
  821. $post_mime_types = array( // array( adj, noun )
  822. 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
  823. 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
  824. 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
  825. );
  826. return apply_filters('post_mime_types', $post_mime_types);
  827. }
  828. /**
  829. * {@internal Missing Short Description}}
  830. *
  831. * @since 2.5.0
  832. *
  833. * @param unknown_type $type
  834. * @return unknown
  835. */
  836. function get_available_post_mime_types($type = 'attachment') {
  837. global $wpdb;
  838. $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
  839. return $types;
  840. }
  841. /**
  842. * {@internal Missing Short Description}}
  843. *
  844. * @since 2.5.0
  845. *
  846. * @param unknown_type $q
  847. * @return unknown
  848. */
  849. function wp_edit_attachments_query( $q = false ) {
  850. if ( false === $q )
  851. $q = $_GET;
  852. $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
  853. $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
  854. $q['post_type'] = 'attachment';
  855. $post_type = get_post_type_object( 'attachment' );
  856. $states = 'inherit';
  857. if ( current_user_can( $post_type->cap->read_private_posts ) )
  858. $states .= ',private';
  859. $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
  860. $media_per_page = (int) get_user_option( 'upload_per_page' );
  861. if ( empty( $media_per_page ) || $media_per_page < 1 )
  862. $media_per_page = 20;
  863. $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
  864. $post_mime_types = get_post_mime_types();
  865. $avail_post_mime_types = get_available_post_mime_types('attachment');
  866. if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
  867. unset($q['post_mime_type']);
  868. if ( isset($q['detached']) )
  869. add_filter('posts_where', '_edit_attachments_query_helper');
  870. wp( $q );
  871. if ( isset($q['detached']) )
  872. remove_filter('posts_where', '_edit_attachments_query_helper');
  873. return array($post_mime_types, $avail_post_mime_types);
  874. }
  875. function _edit_attachments_query_helper($where) {
  876. return $where .= ' AND post_parent < 1';
  877. }
  878. /**
  879. * Returns the list of classes to be used by a metabox
  880. *
  881. * @uses get_user_option()
  882. * @since 2.5.0
  883. *
  884. * @param unknown_type $id
  885. * @param unknown_type $page
  886. * @return unknown
  887. */
  888. function postbox_classes( $id, $page ) {
  889. if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id ) {
  890. $classes = array( '' );
  891. } elseif ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
  892. if ( !is_array( $closed ) ) {
  893. $classes = array( '' );
  894. } else {
  895. $classes = in_array( $id, $closed ) ? array( 'closed' ) : array( '' );
  896. }
  897. } else {
  898. $classes = array( '' );
  899. }
  900. $classes = apply_filters( "postbox_classes_{$page}_{$id}", $classes );
  901. return implode( ' ', $classes );
  902. }
  903. /**
  904. * {@internal Missing Short Description}}
  905. *
  906. * @since 2.5.0
  907. *
  908. * @param int|object $id Post ID or post object.
  909. * @param string $title (optional) Title
  910. * @param string $name (optional) Name
  911. * @return array With two entries of type string
  912. */
  913. function get_sample_permalink($id, $title = null, $name = null) {
  914. $post = &get_post($id);
  915. if ( !$post->ID )
  916. return array('', '');
  917. $ptype = get_post_type_object($post->post_type);
  918. $original_status = $post->post_status;
  919. $original_date = $post->post_date;
  920. $original_name = $post->post_name;
  921. // Hack: get_permalink would return ugly permalink for
  922. // drafts, so we will fake, that our post is published
  923. if ( in_array($post->post_status, array('draft', 'pending')) ) {
  924. $post->post_status = 'publish';
  925. $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
  926. }
  927. // If the user wants to set a new name -- override the current one
  928. // Note: if empty name is supplied -- use the title instead, see #6072
  929. if ( !is_null($name) )
  930. $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
  931. $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
  932. $post->filter = 'sample';
  933. $permalink = get_permalink($post, true);
  934. // Replace custom post_type Token with generic pagename token for ease of use.
  935. $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
  936. // Handle page hierarchy
  937. if ( $ptype->hierarchical ) {
  938. $uri = get_page_uri($post);
  939. $uri = untrailingslashit($uri);
  940. $uri = strrev( stristr( strrev( $uri ), '/' ) );
  941. $uri = untrailingslashit($uri);
  942. $uri = apply_filters( 'editable_slug', $uri );
  943. if ( !empty($uri) )
  944. $uri .= '/';
  945. $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
  946. }
  947. $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
  948. $post->post_status = $original_status;
  949. $post->post_date = $original_date;
  950. $post->post_name = $original_name;
  951. unset($post->filter);
  952. return $permalink;
  953. }
  954. /**
  955. * sample permalink html
  956. *
  957. * intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
  958. *
  959. * @since 2.5.0
  960. *
  961. * @param int|object $id Post ID or post object.
  962. * @param string $new_title (optional) New title
  963. * @param string $new_slug (optional) New slug
  964. * @return string intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
  965. */
  966. function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
  967. global $wpdb;
  968. $post = &get_post($id);
  969. list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
  970. if ( 'publish' == $post->post_status ) {
  971. $ptype = get_post_type_object($post->post_type);
  972. $view_post = $ptype->labels->view_item;
  973. $title = __('Click to edit this part of the permalink');
  974. } else {
  975. $title = __('Temporary permalink. Click to edit this part.');
  976. }
  977. if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
  978. $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
  979. if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
  980. $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
  981. if ( isset($view_post) )
  982. $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
  983. $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
  984. return $return;
  985. }
  986. if ( function_exists('mb_strlen') ) {
  987. if ( mb_strlen($post_name) > 30 ) {
  988. $post_name_abridged = mb_substr($post_name, 0, 14). '&hellip;' . mb_substr($post_name, -14);
  989. } else {
  990. $post_name_abridged = $post_name;
  991. }
  992. } else {
  993. if ( strlen($post_name) > 30 ) {
  994. $post_name_abridged = substr($post_name, 0, 14). '&hellip;' . substr($post_name, -14);
  995. } else {
  996. $post_name_abridged = $post_name;
  997. }
  998. }
  999. $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
  1000. $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
  1001. $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
  1002. $return = '<strong>' . __('Permalink:') . "</strong>\n";
  1003. $return .= '<span id="sample-permalink">' . $display_link . "</span>\n";
  1004. $return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
  1005. $return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button hide-if-no-js" onclick="editPermalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
  1006. $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
  1007. if ( isset($view_post) )
  1008. $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
  1009. $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
  1010. return $return;
  1011. }
  1012. /**
  1013. * Output HTML for the post thumbnail meta-box.
  1014. *
  1015. * @since 2.9.0
  1016. *
  1017. * @param int $thumbnail_id ID of the attachment used for thumbnail
  1018. * @return string html
  1019. */
  1020. function _wp_post_thumbnail_html( $thumbnail_id = NULL ) {
  1021. global $content_width, $_wp_additional_image_sizes, $post_ID;
  1022. $set_thumbnail_link = '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set featured image' ) . '" href="' . esc_url( get_upload_iframe_src('image') ) . '" id="set-post-thumbnail" class="thickbox">%s</a></p>';
  1023. $content = sprintf($set_thumbnail_link, esc_html__( 'Set featured image' ));
  1024. if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
  1025. $old_content_width = $content_width;
  1026. $content_width = 266;
  1027. if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
  1028. $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
  1029. else
  1030. $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
  1031. if ( !empty( $thumbnail_html ) ) {
  1032. $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" );
  1033. $content = sprintf($set_thumbnail_link, $thumbnail_html);
  1034. $content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail" onclick="WPRemoveThumbnail(\'' . $ajax_nonce . '\');return false;">' . esc_html__( 'Remove featured image' ) . '</a></p>';
  1035. }
  1036. $content_width = $old_content_width;
  1037. }
  1038. return apply_filters( 'admin_post_thumbnail_html', $content );
  1039. }
  1040. /**
  1041. * Check to see if the post is currently being edited by another user.
  1042. *
  1043. * @since 2.5.0
  1044. *
  1045. * @param int $post_id ID of the post to check for editing
  1046. * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
  1047. */
  1048. function wp_check_post_lock( $post_id ) {
  1049. if ( !$post = get_post( $post_id ) )
  1050. return false;
  1051. if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
  1052. return false;
  1053. $lock = explode( ':', $lock );
  1054. $time = $lock[0];
  1055. $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
  1056. $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
  1057. if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
  1058. return $user;
  1059. return false;
  1060. }
  1061. /**
  1062. * Mark the post as currently being edited by the current user
  1063. *
  1064. * @since 2.5.0
  1065. *
  1066. * @param int $post_id ID of the post to being edited
  1067. * @return bool Returns false if the post doesn't exist of there is no current user
  1068. */
  1069. function wp_set_post_lock( $post_id ) {
  1070. if ( !$post = get_post( $post_id ) )
  1071. return false;
  1072. if ( 0 == ($user_id = get_current_user_id()) )
  1073. return false;
  1074. $now = time();
  1075. $lock = "$now:$user_id";
  1076. update_post_meta( $post->ID, '_edit_lock', $lock );
  1077. }
  1078. /**
  1079. * Outputs the notice message to say that someone else is editing this post at the moment.
  1080. *
  1081. * @since 2.8.5
  1082. * @return none
  1083. */
  1084. function _admin_notice_post_locked() {
  1085. global $post;
  1086. $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
  1087. $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
  1088. $last_user = get_userdata( $user );
  1089. $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
  1090. switch ($post->post_type) {
  1091. case 'post':
  1092. $message = __( 'Warning: %s is currently editing this post' );
  1093. break;
  1094. case 'page':
  1095. $message = __( 'Warning: %s is currently editing this page' );
  1096. break;
  1097. default:
  1098. $message = __( 'Warning: %s is currently editing this.' );
  1099. }
  1100. $message = sprintf( $message, esc_html( $last_user_name ) );
  1101. echo "<div class='error'><p>$message</p></div>";
  1102. }
  1103. /**
  1104. * Creates autosave data for the specified post from $_POST data.
  1105. *
  1106. * @package WordPress
  1107. * @subpackage Post_Revisions
  1108. * @since 2.6.0
  1109. *
  1110. * @uses _wp_translate_postdata()
  1111. * @uses _wp_post_revision_fields()
  1112. *
  1113. * @return unknown
  1114. */
  1115. function wp_create_post_autosave( $post_id ) {
  1116. $translated = _wp_translate_postdata( true );
  1117. if ( is_wp_error( $translated ) )
  1118. return $translated;
  1119. // Only store one autosave. If there is already an autosave, overwrite it.
  1120. if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
  1121. $new_autosave = _wp_post_revision_fields( $_POST, true );
  1122. $new_autosave['ID'] = $old_autosave->ID;
  1123. $new_autosave['post_author'] = get_current_user_id();
  1124. return wp_update_post( $new_autosave );
  1125. }
  1126. // _wp_put_post_revision() expects unescaped.
  1127. $_POST = stripslashes_deep($_POST);
  1128. // Otherwise create the new autosave as a special post revision
  1129. return _wp_put_post_revision( $_POST, true );
  1130. }
  1131. /**
  1132. * Save draft or manually autosave for showing preview.
  1133. *
  1134. * @package WordPress
  1135. * @since 2.7.0
  1136. *
  1137. * @uses wp_write_post()
  1138. * @uses edit_post()
  1139. * @uses get_post()
  1140. * @uses current_user_can()
  1141. * @uses wp_create_post_autosave()
  1142. *
  1143. * @return str URL to redirect to show the preview
  1144. */
  1145. function post_preview() {
  1146. $post_ID = (int) $_POST['post_ID'];
  1147. $status = get_post_status( $post_ID );
  1148. if ( 'auto-draft' == $status )
  1149. wp_die( __('Preview not available. Please save as a draft first.') );
  1150. if ( isset($_POST['catslist']) )
  1151. $_POST['post_category'] = explode(",", $_POST['catslist']);
  1152. if ( isset($_POST['tags_input']) )
  1153. $_POST['tags_input'] = explode(",", $_POST['tags_input']);
  1154. if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
  1155. unset($_POST['post_category']);
  1156. $_POST['ID'] = $post_ID;
  1157. $post = get_post($post_ID);
  1158. if ( 'page' == $post->post_type ) {
  1159. if ( !current_user_can('edit_page', $post_ID) )
  1160. wp_die(__('You are not allowed to edit this page.'));
  1161. } else {
  1162. if ( !current_user_can('edit_post', $post_ID) )
  1163. wp_die(__('You are not allowed to edit this post.'));
  1164. }
  1165. if ( 'draft' == $post->post_status ) {
  1166. $id = edit_post();
  1167. } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
  1168. $id = wp_create_post_autosave( $post->ID );
  1169. if ( ! is_wp_error($id) )
  1170. $id = $post->ID;
  1171. }
  1172. if ( is_wp_error($id) )
  1173. wp_die( $id->get_error_message() );
  1174. if ( $_POST['post_status'] == 'draft' ) {
  1175. $url = add_query_arg( 'preview', 'true', get_permalink($id) );
  1176. } else {
  1177. $nonce = wp_create_nonce('post_preview_' . $id);
  1178. $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
  1179. }
  1180. return $url;
  1181. }
  1182. /**
  1183. * Adds the TinyMCE editor used on the Write and Edit screens.
  1184. *
  1185. * @package WordPress
  1186. * @since 2.7.0
  1187. *
  1188. * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
  1189. * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
  1190. * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
  1191. * to the URL when queueing them with the mce_external_plugins filter.
  1192. *
  1193. * @param bool $teeny optional Output a trimmed down version used in Press This.
  1194. * @param mixed $settings optional An array that can add to or overwrite the default TinyMCE settings.
  1195. */
  1196. function wp_tiny_mce( $teeny = false, $settings = false ) {
  1197. global $concatenate_scripts, $compress_scripts, $tinymce_version, $editor_styles;
  1198. if ( ! user_can_richedit() )
  1199. return;
  1200. $baseurl = includes_url('js/tinymce');
  1201. $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
  1202. /*
  1203. The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
  1204. By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
  1205. The + sign marks the default language. More information:
  1206. http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
  1207. */
  1208. $mce_spellchecker_languages = apply_filters('mce_spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv');
  1209. if ( $teeny ) {
  1210. $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs') );
  1211. $ext_plugins = '';
  1212. } else {
  1213. $plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'wordpress', 'wpfullscreen', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
  1214. /*
  1215. The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
  1216. It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
  1217. The url should be absolute and should include the js file name to be loaded. Example:
  1218. array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
  1219. If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
  1220. */
  1221. $mce_external_plugins = apply_filters('mce_external_plugins', array());
  1222. $ext_plugins = '';
  1223. if ( ! empty($mce_external_plugins) ) {
  1224. /*
  1225. The following filter loads external language files for TinyMCE plugins.
  1226. It takes an associative array 'plugin_name' => 'path', where path is the
  1227. include path to the file. The language file should follow the same format as
  1228. /tinymce/langs/wp-langs.php and should define a variable $strings that
  1229. holds all translated strings.
  1230. When this filter is not used, the function will try to load {mce_locale}.js.
  1231. If that is not found, en.js will be tried next.
  1232. */
  1233. $mce_external_languages = apply_filters('mce_external_languages', array());
  1234. $loaded_langs = array();
  1235. $strings = '';
  1236. if ( ! empty($mce_external_languages) ) {
  1237. foreach ( $mce_external_languages as $name => $path ) {
  1238. if ( @is_file($path) && @is_readable($path) ) {
  1239. include_once($path);
  1240. $ext_plugins .= $strings . "\n";
  1241. $loaded_langs[] = $name;
  1242. }
  1243. }
  1244. }
  1245. foreach ( $mce_external_plugins as $name => $url ) {
  1246. if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
  1247. $plugins[] = '-' . $name;
  1248. $plugurl = dirname($url);
  1249. $strings = $str1 = $str2 = '';
  1250. if ( ! in_array($name, $loaded_langs) ) {
  1251. $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
  1252. $path = WP_PLUGIN_DIR . $path . '/langs/';
  1253. if ( function_exists('realpath') )
  1254. $path = trailingslashit( realpath($path) );
  1255. if ( @is_file($path . $mce_locale . '.js') )
  1256. $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
  1257. if ( @is_file($path . $mce_locale . '_dlg.js') )
  1258. $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
  1259. if ( 'en' != $mce_locale && empty($strings) ) {
  1260. if ( @is_file($path . 'en.js') ) {
  1261. $str1 = @file_get_contents($path . 'en.js');
  1262. $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
  1263. }
  1264. if ( @is_file($path . 'en_dlg.js') ) {
  1265. $str2 = @file_get_contents($path . 'en_dlg.js');
  1266. $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
  1267. }
  1268. }
  1269. if ( ! empty($strings) )
  1270. $ext_plugins .= "\n" . $strings . "\n";
  1271. }
  1272. $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
  1273. $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
  1274. }
  1275. }
  1276. }
  1277. if ( $teeny ) {
  1278. $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
  1279. $mce_buttons = implode($mce_buttons, ',');
  1280. $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = ''

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