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

/wp-admin/includes/post.php

https://github.com/coffeant/wordpress
PHP | 1841 lines | 1167 code | 301 blank | 373 comment | 328 complexity | bfd71f0f7859c9b68ab0bfae16c94134 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1

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

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