3 * WordPress Post Administration API.
6 * @subpackage Administration
10 * Rename $_POST data from form names to DB post columns.
12 * Manipulates $_POST directly.
17 * @param bool $update Are we updating a pre-existing post?
18 * @param post_data array Array of post data. Defaults to the contents of $_POST.
19 * @return object|bool WP_Error on failure, true on success.
21 function _wp_translate_postdata( $update = false, $post_data = null ) {
23 if ( empty($post_data) )
27 $post_data['ID'] = (int) $post_data['post_ID'];
28 $post_data['post_content'] = isset($post_data['content']) ? $post_data['content'] : '';
29 $post_data['post_excerpt'] = isset($post_data['excerpt']) ? $post_data['excerpt'] : '';
30 $post_data['post_parent'] = isset($post_data['parent_id'])? $post_data['parent_id'] : '';
31 if ( isset($post_data['trackback_url']) )
32 $post_data['to_ping'] = $post_data['trackback_url'];
34 if (!empty ( $post_data['post_author_override'] ) ) {
35 $post_data['post_author'] = (int) $post_data['post_author_override'];
37 if (!empty ( $post_data['post_author'] ) ) {
38 $post_data['post_author'] = (int) $post_data['post_author'];
40 $post_data['post_author'] = (int) $post_data['user_ID'];
44 if ( isset($post_data['user_ID']) && ($post_data['post_author'] != $post_data['user_ID']) ) {
45 if ( 'page' == $post_data['post_type'] ) {
46 if ( !current_user_can( 'edit_others_pages' ) ) {
47 return new WP_Error( 'edit_others_pages', $update ?
48 __( 'You are not allowed to edit pages as this user.' ) :
49 __( 'You are not allowed to create pages as this user.' )
53 if ( !current_user_can( 'edit_others_posts' ) ) {
54 return new WP_Error( 'edit_others_posts', $update ?
55 __( 'You are not allowed to edit posts as this user.' ) :
56 __( 'You are not allowed to post as this user.' )
62 // What to do based on which button they pressed
63 if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
64 $post_data['post_status'] = 'draft';
65 if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
66 $post_data['post_status'] = 'private';
67 if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( $post_data['post_status'] != 'private' ) )
68 $post_data['post_status'] = 'publish';
69 if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
70 $post_data['post_status'] = 'draft';
71 if ( isset($post_data['pending']) && '' != $post_data['pending'] )
72 $post_data['post_status'] = 'pending';
74 $previous_status = get_post_field('post_status', isset($post_data['ID']) ? $post_data['ID'] : $post_data['temp_ID']);
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 ( 'page' == $post_data['post_type'] ) {
79 $publish_cap = 'publish_pages';
80 $edit_cap = 'edit_published_pages';
82 $publish_cap = 'publish_posts';
83 $edit_cap = 'edit_published_posts';
85 if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $publish_cap )) )
86 if ( $previous_status != 'publish' || !current_user_can( $edit_cap ) )
87 $post_data['post_status'] = 'pending';
89 if ( ! isset($post_data['post_status']) )
90 $post_data['post_status'] = $previous_status;
92 if (!isset( $post_data['comment_status'] ))
93 $post_data['comment_status'] = 'closed';
95 if (!isset( $post_data['ping_status'] ))
96 $post_data['ping_status'] = 'closed';
98 foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
99 if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
100 $post_data['edit_date'] = '1';
105 if ( !empty( $post_data['edit_date'] ) ) {
106 $aa = $post_data['aa'];
107 $mm = $post_data['mm'];
108 $jj = $post_data['jj'];
109 $hh = $post_data['hh'];
110 $mn = $post_data['mn'];
111 $ss = $post_data['ss'];
112 $aa = ($aa <= 0 ) ? date('Y') : $aa;
113 $mm = ($mm <= 0 ) ? date('n') : $mm;
114 $jj = ($jj > 31 ) ? 31 : $jj;
115 $jj = ($jj <= 0 ) ? date('j') : $jj;
116 $hh = ($hh > 23 ) ? $hh -24 : $hh;
117 $mn = ($mn > 59 ) ? $mn -60 : $mn;
118 $ss = ($ss > 59 ) ? $ss -60 : $ss;
119 $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
120 $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
127 * Update an existing post with values provided in $_POST.
131 * @param array $post_data Optional.
132 * @return int Post ID.
134 function edit_post( $post_data = null ) {
136 if ( empty($post_data) )
137 $post_data = &$_POST;
139 $post_ID = (int) $post_data['post_ID'];
141 if ( 'page' == $post_data['post_type'] ) {
142 if ( !current_user_can( 'edit_page', $post_ID ) )
143 wp_die( __('You are not allowed to edit this page.' ));
145 if ( !current_user_can( 'edit_post', $post_ID ) )
146 wp_die( __('You are not allowed to edit this post.' ));
149 // Autosave shouldn't save too soon after a real save
150 if ( 'autosave' == $post_data['action'] ) {
151 $post =& get_post( $post_ID );
153 $then = strtotime($post->post_date_gmt . ' +0000');
154 $delta = AUTOSAVE_INTERVAL / 2;
155 if ( ($now - $then) < $delta )
159 $post_data = _wp_translate_postdata( true, $post_data );
160 if ( is_wp_error($post_data) )
161 wp_die( $post_data->get_error_message() );
163 if ( isset($post_data['visibility']) ) {
164 switch ( $post_data['visibility'] ) {
166 $post_data['post_password'] = '';
169 unset( $post_data['sticky'] );
172 $post_data['post_status'] = 'private';
173 $post_data['post_password'] = '';
174 unset( $post_data['sticky'] );
180 if ( isset($post_data['meta']) && $post_data['meta'] ) {
181 foreach ( $post_data['meta'] as $key => $value )
182 update_meta( $key, $value['key'], $value['value'] );
185 if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
186 foreach ( $post_data['deletemeta'] as $key => $value )
190 add_meta( $post_ID );
192 wp_update_post( $post_data );
194 // Reunite any orphaned attachments with their parent
195 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
196 $draft_ids = array();
197 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
198 _relocate_children( $draft_temp_id, $post_ID );
200 // Now that we have an ID we can fix any attachment anchor hrefs
201 _fix_attachment_links( $post_ID );
203 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
205 if ( current_user_can( 'edit_others_posts' ) ) {
206 if ( !empty($post_data['sticky']) )
207 stick_post($post_ID);
209 unstick_post($post_ID);
216 * {@internal Missing Short Description}}
218 * Updates all bulk edited posts/pages, adding (but not removing) tags and
219 * categories. Skips pages when they would be their own parent or child.
225 function bulk_edit_posts( $post_data = null ) {
228 if ( empty($post_data) )
229 $post_data = &$_POST;
231 if ( isset($post_data['post_type']) && 'page' == $post_data['post_type'] ) {
232 if ( ! current_user_can( 'edit_pages' ) )
233 wp_die( __('You are not allowed to edit pages.') );
235 if ( ! current_user_can( 'edit_posts' ) )
236 wp_die( __('You are not allowed to edit posts.') );
239 $post_IDs = array_map( 'intval', (array) $post_data['post'] );
241 $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tags_input', 'post_category', 'sticky' );
242 foreach ( $reset as $field ) {
243 if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
244 unset($post_data[$field]);
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'] );
251 unset($post_data['post_category']);
254 if ( isset($post_data['tags_input']) ) {
255 $new_tags = preg_replace( '/\s*,\s*/', ',', rtrim( trim($post_data['tags_input']), ' ,' ) );
256 $new_tags = explode(',', $new_tags);
259 if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
260 $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
263 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
264 $children[] = $parent;
266 foreach ( $pages as $page ) {
267 if ( $page->ID == $parent ) {
268 $parent = $page->post_parent;
275 $updated = $skipped = $locked = array();
276 foreach ( $post_IDs as $post_ID ) {
278 if ( isset($children) && in_array($post_ID, $children) ) {
279 $skipped[] = $post_ID;
283 if ( wp_check_post_lock( $post_ID ) ) {
284 $locked[] = $post_ID;
288 if ( isset($new_cats) ) {
289 $cats = (array) wp_get_post_categories($post_ID);
290 $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
293 if ( isset($new_tags) ) {
294 $tags = wp_get_post_tags($post_ID, array('fields' => 'names'));
295 $post_data['tags_input'] = array_unique( array_merge($tags, $new_tags) );
298 $post_data['ID'] = $post_ID;
299 $updated[] = wp_update_post( $post_data );
301 if ( current_user_can( 'edit_others_posts' ) && isset( $post_data['sticky'] ) ) {
302 if ( 'sticky' == $post_data['sticky'] )
303 stick_post( $post_ID );
305 unstick_post( $post_ID );
310 return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
314 * Default post information to use when populating the "Write Post" form.
320 function get_default_post_to_edit() {
321 if ( !empty( $_REQUEST['post_title'] ) )
322 $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
323 else if ( !empty( $_REQUEST['popuptitle'] ) ) {
324 $post_title = esc_html( stripslashes( $_REQUEST['popuptitle'] ));
325 $post_title = funky_javascript_fix( $post_title );
331 if ( !empty( $_REQUEST['content'] ) )
332 $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
333 else if ( !empty( $post_title ) ) {
334 $text = esc_html( stripslashes( urldecode( $_REQUEST['text'] ) ) );
335 $text = funky_javascript_fix( $text);
336 $popupurl = esc_url($_REQUEST['popupurl']);
337 $post_content = '<a href="'.$popupurl.'">'.$post_title.'</a>'."\n$text";
340 if ( !empty( $_REQUEST['excerpt'] ) )
341 $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
346 $post->post_name = '';
347 $post->post_author = '';
348 $post->post_date = '';
349 $post->post_date_gmt = '';
350 $post->post_password = '';
351 $post->post_status = 'draft';
352 $post->post_type = 'post';
355 $post->comment_status = get_option( 'default_comment_status' );
356 $post->ping_status = get_option( 'default_ping_status' );
357 $post->post_pingback = get_option( 'default_pingback_flag' );
358 $post->post_category = get_option( 'default_category' );
359 $post->post_content = apply_filters( 'default_content', $post_content);
360 $post->post_title = apply_filters( 'default_title', $post_title );
361 $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt);
362 $post->page_template = 'default';
363 $post->post_parent = 0;
364 $post->menu_order = 0;
370 * {@internal Missing Short Description}}
376 function get_default_page_to_edit() {
377 $page = get_default_post_to_edit();
378 $page->post_type = 'page';
383 * Get an existing post and format it for editing.
387 * @param unknown_type $id
390 function get_post_to_edit( $id ) {
392 $post = get_post( $id, OBJECT, 'edit' );
394 if ( $post->post_type == 'page' )
395 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
401 * Determine if a post exists based on title, content, and date
405 * @param string $title Post title
406 * @param string $content Optional post content
407 * @param string $date Optional post date
408 * @return int Post ID if post exists, 0 otherwise.
410 function post_exists($title, $content = '', $date = '') {
413 $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
414 $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
415 $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
417 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
420 if ( !empty ( $date ) ) {
421 $query .= ' AND post_date = %s';
422 $args[] = $post_date;
425 if ( !empty ( $title ) ) {
426 $query .= ' AND post_title = %s';
427 $args[] = $post_title;
430 if ( !empty ( $content ) ) {
431 $query .= 'AND post_content = %s';
432 $args[] = $post_content;
435 if ( !empty ( $args ) )
436 return $wpdb->get_var( $wpdb->prepare($query, $args) );
442 * Creates a new post from the "Write Post" form using $_POST information.
448 function wp_write_post() {
451 if ( 'page' == $_POST['post_type'] ) {
452 if ( !current_user_can( 'edit_pages' ) )
453 return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this blog.' ) );
455 if ( !current_user_can( 'edit_posts' ) )
456 return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this blog.' ) );
460 // Check for autosave collisions
462 if ( isset($_POST['temp_ID']) ) {
463 $temp_id = (int) $_POST['temp_ID'];
464 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
465 $draft_ids = array();
466 foreach ( $draft_ids as $temp => $real )
467 if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
468 unset($draft_ids[$temp]);
470 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
471 $_POST['post_ID'] = $draft_ids[$temp_id];
472 unset($_POST['temp_ID']);
473 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
478 $translated = _wp_translate_postdata( false );
479 if ( is_wp_error($translated) )
482 if ( isset($_POST['visibility']) ) {
483 switch ( $_POST['visibility'] ) {
485 $_POST['post_password'] = '';
488 unset( $_POST['sticky'] );
491 $_POST['post_status'] = 'private';
492 $_POST['post_password'] = '';
493 unset( $_POST['sticky'] );
499 $post_ID = wp_insert_post( $_POST );
500 if ( is_wp_error( $post_ID ) )
503 if ( empty($post_ID) )
506 add_meta( $post_ID );
508 // Reunite any orphaned attachments with their parent
509 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
510 $draft_ids = array();
511 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
512 _relocate_children( $draft_temp_id, $post_ID );
513 if ( $temp_id && $temp_id != $draft_temp_id )
514 _relocate_children( $temp_id, $post_ID );
516 // Update autosave collision detection
518 $draft_ids[$temp_id] = $post_ID;
519 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
522 // Now that we have an ID we can fix any attachment anchor hrefs
523 _fix_attachment_links( $post_ID );
525 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
531 * Calls wp_write_post() and handles the errors.
537 function write_post() {
538 $result = wp_write_post();
539 if( is_wp_error( $result ) )
540 wp_die( $result->get_error_message() );
550 * {@internal Missing Short Description}}
554 * @param unknown_type $post_ID
557 function add_meta( $post_ID ) {
559 $post_ID = (int) $post_ID;
561 $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
563 $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
564 $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
565 $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes( trim( $_POST['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:
571 if ('#NONE#' != $metakeyselect)
572 $metakey = $metakeyselect;
575 $metakey = $metakeyinput; // default
577 if ( in_array($metakey, $protected) )
580 wp_cache_delete($post_ID, 'post_meta');
582 $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value ) VALUES (%s, %s, %s)", $post_ID, $metakey, $metavalue) );
583 return $wpdb->insert_id;
589 * {@internal Missing Short Description}}
593 * @param unknown_type $mid
596 function delete_meta( $mid ) {
600 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
601 wp_cache_delete($post_id, 'post_meta');
603 return $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
607 * Get a list of previously defined keys.
613 function get_meta_keys() {
616 $keys = $wpdb->get_col( "
620 ORDER BY meta_key" );
626 * {@internal Missing Short Description}}
630 * @param unknown_type $mid
633 function get_post_meta_by_id( $mid ) {
637 $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
638 if ( is_serialized_string( $meta->meta_value ) )
639 $meta->meta_value = maybe_unserialize( $meta->meta_value );
644 * {@internal Missing Short Description}}
646 * Some postmeta stuff.
650 * @param unknown_type $postid
653 function has_meta( $postid ) {
656 return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
657 FROM $wpdb->postmeta WHERE post_id = %d
658 ORDER BY meta_key,meta_id", $postid), ARRAY_A );
663 * {@internal Missing Short Description}}
667 * @param unknown_type $meta_id
668 * @param unknown_type $meta_key
669 * @param unknown_type $meta_value
672 function update_meta( $meta_id, $meta_key, $meta_value ) {
675 $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
677 if ( in_array($meta_key, $protected) )
680 if ( '' === trim( $meta_value ) )
683 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
684 wp_cache_delete($post_id, 'post_meta');
686 $meta_value = maybe_serialize( stripslashes( $meta_value ) );
687 $meta_id = (int) $meta_id;
689 $data = compact( 'meta_key', 'meta_value' );
690 $where = compact( 'meta_id' );
692 return $wpdb->update( $wpdb->postmeta, $data, $where );
700 * Replace hrefs of attachment anchors with up-to-date permalinks.
705 * @param unknown_type $post_ID
708 function _fix_attachment_links( $post_ID ) {
710 $post = & get_post( $post_ID, ARRAY_A );
712 $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
714 // See if we have any rel="attachment" links
715 if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
719 $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
720 foreach ( $anchor_matches[0] as $anchor ) {
721 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
724 $id = (int) $id_matches[3];
726 // While we have the attachment ID, let's adopt any orphans.
727 $attachment = & get_post( $id, ARRAY_A );
728 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
729 $attachment['post_parent'] = $post_ID;
730 // Escape data pulled from DB.
731 $attachment = add_magic_quotes( $attachment);
732 wp_update_post( $attachment);
735 $post_search[$i] = $anchor;
736 $post_replace[$i] = preg_replace( "#href=(\"|')[^'\"]*\\1#e", "stripslashes( 'href=\\1' ).get_attachment_link( $id ).stripslashes( '\\1' )", $anchor );
740 $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
742 // Escape data pulled from DB.
743 $post = add_magic_quotes( $post);
745 return wp_update_post( $post);
749 * Move child posts to a new parent.
754 * @param unknown_type $old_ID
755 * @param unknown_type $new_ID
758 function _relocate_children( $old_ID, $new_ID ) {
760 $old_ID = (int) $old_ID;
761 $new_ID = (int) $new_ID;
762 return $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('post_parent' => $old_ID) );
766 * {@internal Missing Short Description}}
770 * @param unknown_type $type
773 function get_available_post_statuses($type = 'post') {
774 $stati = wp_count_posts($type);
776 return array_keys(get_object_vars($stati));
780 * {@internal Missing Short Description}}
784 * @param unknown_type $q
787 function wp_edit_posts_query( $q = false ) {
790 $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
791 $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
792 $post_stati = array( // array( adj, noun )
793 'publish' => array(_x('Published', 'post'), __('Published posts'), _n_noop('Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>')),
794 'future' => array(_x('Scheduled', 'post'), __('Scheduled posts'), _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>')),
795 'pending' => array(_x('Pending Review', 'post'), __('Pending posts'), _n_noop('Pending Review <span class="count">(%s)</span>', 'Pending Review <span class="count">(%s)</span>')),
796 'draft' => array(_x('Draft', 'post'), _x('Drafts', 'manage posts header'), _n_noop('Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>')),
797 'private' => array(_x('Private', 'post'), __('Private posts'), _n_noop('Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>')),
800 $post_stati = apply_filters('post_stati', $post_stati);
802 $avail_post_stati = get_available_post_statuses('post');
805 if ( isset($q['post_status']) && in_array( $q['post_status'], array_keys($post_stati) ) ) {
806 $post_status_q = '&post_status=' . $q['post_status'];
807 $post_status_q .= '&perm=readable';
810 if ( isset($q['post_status']) && 'pending' === $q['post_status'] ) {
812 $orderby = 'modified';
813 } elseif ( isset($q['post_status']) && 'draft' === $q['post_status'] ) {
815 $orderby = 'modified';
821 $posts_per_page = get_user_option('edit_per_page');
822 if ( empty($posts_per_page) )
823 $posts_per_page = 15;
824 $posts_per_page = apply_filters('edit_posts_per_page', $posts_per_page);
826 wp("post_type=post&$post_status_q&posts_per_page=$posts_per_page&order=$order&orderby=$orderby");
828 return array($post_stati, $avail_post_stati);
832 * {@internal Missing Short Description}}
836 * @param unknown_type $type
839 function get_available_post_mime_types($type = 'attachment') {
842 $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
847 * {@internal Missing Short Description}}
851 * @param unknown_type $q
854 function wp_edit_attachments_query( $q = false ) {
858 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
859 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
860 $q['post_type'] = 'attachment';
861 $q['post_status'] = 'any';
862 $media_per_page = get_user_option('upload_per_page');
863 if ( empty($media_per_page) )
864 $media_per_page = 20;
865 $q['posts_per_page'] = $media_per_page;
866 $post_mime_types = array( // array( adj, noun )
867 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
868 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
869 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
871 $post_mime_types = apply_filters('post_mime_types', $post_mime_types);
873 $avail_post_mime_types = get_available_post_mime_types('attachment');
875 if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
876 unset($q['post_mime_type']);
880 return array($post_mime_types, $avail_post_mime_types);
884 * {@internal Missing Short Description}}
888 * @param unknown_type $id
889 * @param unknown_type $page
892 function postbox_classes( $id, $page ) {
893 if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id )
895 $current_user = wp_get_current_user();
896 if ( $closed = get_user_option('closedpostboxes_'.$page, 0, false ) ) {
897 if ( !is_array( $closed ) ) return '';
898 return in_array( $id, $closed )? 'closed' : '';
905 * {@internal Missing Short Description}}
909 * @param unknown_type $id
910 * @param unknown_type $title
911 * @param unknown_type $name
914 function get_sample_permalink($id, $title=null, $name = null) {
915 $post = &get_post($id);
917 return array('', '');
919 $original_status = $post->post_status;
920 $original_date = $post->post_date;
921 $original_name = $post->post_name;
923 // Hack: get_permalink would return ugly permalink for
924 // drafts, so we will fake, that our post is published
925 if (in_array($post->post_status, array('draft', 'pending'))) {
926 $post->post_status = 'publish';
927 $post->post_name = sanitize_title($post->post_name? $post->post_name : $post->post_title, $post->ID);
930 $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
932 // If the user wants to set a new name -- override the current one
933 // Note: if empty name is supplied -- use the title instead, see #6072
934 if (!is_null($name)) {
935 $post->post_name = sanitize_title($name? $name : $title, $post->ID);
938 $post->filter = 'sample';
940 $permalink = get_permalink($post, true);
942 // Handle page hierarchy
943 if ( 'page' == $post->post_type ) {
944 $uri = get_page_uri($post->ID);
945 $uri = untrailingslashit($uri);
946 $uri = strrev( stristr( strrev( $uri ), '/' ) );
947 $uri = untrailingslashit($uri);
950 $permalink = str_replace('%pagename%', "${uri}%pagename%", $permalink);
953 $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
954 $post->post_status = $original_status;
955 $post->post_date = $original_date;
956 $post->post_name = $original_name;
957 unset($post->filter);
963 * {@internal Missing Short Description}}
967 * @param unknown_type $id
968 * @param unknown_type $new_title
969 * @param unknown_type $new_slug
972 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
973 $post = &get_post($id);
974 list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
975 if ( 'publish' == $post->post_status )
976 $view_post = 'post' == $post->post_type ? __('View Post') : __('View Page');
978 if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
979 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
980 if ( current_user_can( 'manage_options' ) )
981 $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
982 if ( isset($view_post) )
983 $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
988 $title = __('Click to edit this part of the permalink');
989 if (function_exists('mb_strlen')) {
990 if (mb_strlen($post_name) > 30) {
991 $post_name_abridged = mb_substr($post_name, 0, 14). '…' . mb_substr($post_name, -14);
993 $post_name_abridged = $post_name;
996 if (strlen($post_name) > 30) {
997 $post_name_abridged = substr($post_name, 0, 14). '…' . substr($post_name, -14);
999 $post_name_abridged = $post_name;
1003 $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
1004 $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
1005 $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
1006 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $display_link . "</span>\n";
1007 $return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button hide-if-no-js" onclick="edit_permalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
1008 $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
1009 if ( isset($view_post) )
1010 $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
1016 * {@internal Missing Short Description}}
1020 * @param unknown_type $post_id
1021 * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
1023 function wp_check_post_lock( $post_id ) {
1024 global $current_user;
1026 if ( !$post = get_post( $post_id ) )
1029 $lock = get_post_meta( $post->ID, '_edit_lock', true );
1030 $last = get_post_meta( $post->ID, '_edit_last', true );
1032 $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
1034 if ( $lock && $lock > time() - $time_window && $last != $current_user->ID )
1040 * {@internal Missing Short Description}}
1044 * @param unknown_type $post_id
1047 function wp_set_post_lock( $post_id ) {
1048 global $current_user;
1049 if ( !$post = get_post( $post_id ) )
1051 if ( !$current_user || !$current_user->ID )
1056 if ( !add_post_meta( $post->ID, '_edit_lock', $now, true ) )
1057 update_post_meta( $post->ID, '_edit_lock', $now );
1058 if ( !add_post_meta( $post->ID, '_edit_last', $current_user->ID, true ) )
1059 update_post_meta( $post->ID, '_edit_last', $current_user->ID );
1063 * Outputs the notice message to say that someone else is editing this post at the moment.
1068 function _admin_notice_post_locked() {
1070 $last_user = get_userdata( get_post_meta( $post->ID, '_edit_last', true ) );
1071 $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
1073 switch ($post->post_type) {
1075 $message = __( 'Warning: %s is currently editing this post' );
1078 $message = __( 'Warning: %s is currently editing this page' );
1081 $message = __( 'Warning: %s is currently editing this.' );
1084 $message = sprintf( $message, esc_html( $last_user_name ) );
1085 echo "<div class='error'><p>$message</p></div>";
1089 * Creates autosave data for the specified post from $_POST data.
1091 * @package WordPress
1092 * @subpackage Post_Revisions
1095 * @uses _wp_translate_postdata()
1096 * @uses _wp_post_revision_fields()
1098 function wp_create_post_autosave( $post_id ) {
1099 $translated = _wp_translate_postdata( true );
1100 if ( is_wp_error( $translated ) )
1103 // Only store one autosave. If there is already an autosave, overwrite it.
1104 if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1105 $new_autosave = _wp_post_revision_fields( $_POST, true );
1106 $new_autosave['ID'] = $old_autosave->ID;
1107 return wp_update_post( $new_autosave );
1110 // _wp_put_post_revision() expects unescaped.
1111 $_POST = stripslashes_deep($_POST);
1113 // Otherwise create the new autosave as a special post revision
1114 return _wp_put_post_revision( $_POST, true );
1118 * Save draft or manually autosave for showing preview.
1120 * @package WordPress
1123 * @uses wp_write_post()
1126 * @uses current_user_can()
1127 * @uses wp_create_post_autosave()
1129 * @return str URL to redirect to show the preview
1131 function post_preview() {
1133 $post_ID = (int) $_POST['post_ID'];
1135 wp_die( __('Preview not available. Please save as a draft first.') );
1137 if ( isset($_POST['catslist']) )
1138 $_POST['post_category'] = explode(",", $_POST['catslist']);
1140 if ( isset($_POST['tags_input']) )
1141 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1143 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1144 unset($_POST['post_category']);
1146 $_POST['ID'] = $post_ID;
1147 $post = get_post($post_ID);
1149 if ( 'page' == $post->post_type ) {
1150 if ( !current_user_can('edit_page', $post_ID) )
1151 wp_die(__('You are not allowed to edit this page.'));
1153 if ( !current_user_can('edit_post', $post_ID) )
1154 wp_die(__('You are not allowed to edit this post.'));
1157 if ( 'draft' == $post->post_status ) {
1159 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
1160 $id = wp_create_post_autosave( $post->ID );
1161 if ( ! is_wp_error($id) )
1165 if ( is_wp_error($id) )
1166 wp_die( $id->get_error_message() );
1168 if ( $_POST['post_status'] == 'draft' ) {
1169 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1171 $nonce = wp_create_nonce('post_preview_' . $id);
1172 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1179 * Adds the TinyMCE editor used on the Write and Edit screens.
1181 * @package WordPress
1184 * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
1185 * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
1186 * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
1187 * to the URL when queueing them with the mce_external_plugins filter.
1189 * @param bool $teeny optional Output a trimmed down version used in Press This.
1191 function wp_tiny_mce( $teeny = false ) {
1192 global $concatenate_scripts, $compress_scripts, $tinymce_version;
1194 if ( ! user_can_richedit() )
1197 $baseurl = includes_url('js/tinymce');
1199 $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1202 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1203 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1204 The + sign marks the default language. More information:
1205 http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1207 $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');
1210 $plugins = apply_filters( 'teeny_mce_plugins', array('safari', 'inlinepopups', 'media', 'autosave', 'fullscreen') );
1213 $plugins = array( 'safari', 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'media', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus' );
1216 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1217 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1218 The url should be absolute and should include the js file name to be loaded. Example:
1219 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1220 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1222 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1225 if ( ! empty($mce_external_plugins) ) {
1228 The following filter loads external language files for TinyMCE plugins.
1229 It takes an associative array 'plugin_name' => 'path', where path is the
1230 include path to the file. The language file should follow the same format as
1231 /tinymce/langs/wp-langs.php and should define a variable $strings that
1232 holds all translated strings.
1233 When this filter is not used, the function will try to load {mce_locale}.js.
1234 If that is not found, en.js will be tried next.
1236 $mce_external_languages = apply_filters('mce_external_languages', array());
1238 $loaded_langs = array();
1241 if ( ! empty($mce_external_languages) ) {
1242 foreach ( $mce_external_languages as $name => $path ) {
1243 if ( @is_file($path) && @is_readable($path) ) {
1244 include_once($path);
1245 $ext_plugins .= $strings . "\n";
1246 $loaded_langs[] = $name;
1251 foreach ( $mce_external_plugins as $name => $url ) {
1253 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1255 $plugins[] = '-' . $name;
1257 $plugurl = dirname($url);
1258 $strings = $str1 = $str2 = '';
1259 if ( ! in_array($name, $loaded_langs) ) {
1260 $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1261 $path = WP_PLUGIN_DIR . $path . '/langs/';
1263 if ( function_exists('realpath') )
1264 $path = trailingslashit( realpath($path) );
1266 if ( @is_file($path . $mce_locale . '.js') )
1267 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1269 if ( @is_file($path . $mce_locale . '_dlg.js') )
1270 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1272 if ( 'en' != $mce_locale && empty($strings) ) {
1273 if ( @is_file($path . 'en.js') ) {
1274 $str1 = @file_get_contents($path . 'en.js');
1275 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1278 if ( @is_file($path . 'en_dlg.js') ) {
1279 $str2 = @file_get_contents($path . 'en_dlg.js');
1280 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1284 if ( ! empty($strings) )
1285 $ext_plugins .= "\n" . $strings . "\n";
1288 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1289 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1294 $plugins = implode($plugins, ',');
1297 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1298 $mce_buttons = implode($mce_buttons, ',');
1299 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1301 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1302 $mce_buttons = implode($mce_buttons, ',');
1304 $mce_buttons_2 = apply_filters('mce_buttons_2', array('formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'media', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' ));
1305 $mce_buttons_2 = implode($mce_buttons_2, ',');
1307 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1308 $mce_buttons_3 = implode($mce_buttons_3, ',');
1310 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1311 $mce_buttons_4 = implode($mce_buttons_4, ',');
1313 $no_captions = ( apply_filters( 'disable_captions', '' ) ) ? true : false;
1315 // TinyMCE init settings
1316 $initArray = array (
1317 'mode' => 'specific_textareas',
1318 'editor_selector' => 'theEditor',
1320 'theme' => 'advanced',
1321 'skin' => 'wp_theme',
1322 'theme_advanced_buttons1' => "$mce_buttons",
1323 'theme_advanced_buttons2' => "$mce_buttons_2",
1324 'theme_advanced_buttons3' => "$mce_buttons_3",
1325 'theme_advanced_buttons4' => "$mce_buttons_4",
1326 'language' => "$mce_locale",
1327 'spellchecker_languages' => "$mce_spellchecker_languages",
1328 'theme_advanced_toolbar_location' => 'top',
1329 'theme_advanced_toolbar_align' => 'left',
1330 'theme_advanced_statusbar_location' => 'bottom',
1331 'theme_advanced_resizing' => true,
1332 'theme_advanced_resize_horizontal' => false,
1333 'dialog_type' => 'modal',
1334 'relative_urls' => false,
1335 'remove_script_host' => false,
1336 'convert_urls' => false,
1337 'apply_source_formatting' => false,
1338 'remove_linebreaks' => true,
1339 'gecko_spellcheck' => true,
1340 'entities' => '38,amp,60,lt,62,gt',
1341 'accessibility_focus' => true,
1342 'tabfocus_elements' => 'major-publishing-actions',
1343 'media_strict' => false,
1344 'save_callback' => 'switchEditors.saveCallback',
1345 'wpeditimage_disable_captions' => $no_captions,
1346 'plugins' => "$plugins"
1349 $mce_css = trim(apply_filters('mce_css', ''), ' ,');
1351 if ( ! empty($mce_css) )
1352 $initArray['content_css'] = "$mce_css";
1354 // For people who really REALLY know what they're doing with TinyMCE
1355 // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1356 // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1357 // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1359 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1361 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1364 if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1365 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1366 $initArray['theme_advanced_buttons4'] = '';
1369 if ( ! isset($concatenate_scripts) )
1370 script_concat_settings();
1372 $language = $initArray['language'];
1373 $zip = $compress_scripts ? 1 : 0;
1378 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1379 * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1380 * If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
1382 $version = apply_filters('tiny_mce_version', '');
1383 $version = 'ver=' . $tinymce_version . $version;
1385 if ( 'en' != $language )
1386 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1389 foreach ( $initArray as $k => $v )
1390 $mce_options .= $k . ':"' . $v . '", ';
1392 $mce_options = rtrim( trim($mce_options), '\n\r,' ); ?>
1394 <script type="text/javascript">
1397 base : "<?php echo $baseurl; ?>",
1399 query : "<?php echo $version; ?>",
1400 mceInit : {<?php echo $mce_options; ?>},
1401 load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1407 if ( $concatenate_scripts )
1408 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=$zip&$version'></script>\n";
1410 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1412 if ( 'en' != $language && isset($lang) )
1413 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1415 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1418 <script type="text/javascript">
1420 <?php if ( $ext_plugins ) echo "$ext_plugins\n"; ?>
1421 <?php if ( $concatenate_scripts ) { ?>
1422 tinyMCEPreInit.go();
1424 (function(){var t=tinyMCEPreInit,sl=tinymce.ScriptLoader,ln=t.mceInit.language,th=t.mceInit.theme,pl=t.mceInit.plugins;sl.markDone(t.base+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'_dlg.js');tinymce.each(pl.split(','),function(n){if(n&&n.charAt(0)!='-'){sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'.js');sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'_dlg.js');}});})();
1426 tinyMCE.init(tinyMCEPreInit.mceInit);