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 * Creates autosave data for the specified post from $_POST data.
1065 * @package WordPress
1066 * @subpackage Post_Revisions
1069 * @uses _wp_translate_postdata()
1070 * @uses _wp_post_revision_fields()
1072 function wp_create_post_autosave( $post_id ) {
1073 $translated = _wp_translate_postdata( true );
1074 if ( is_wp_error( $translated ) )
1077 // Only store one autosave. If there is already an autosave, overwrite it.
1078 if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1079 $new_autosave = _wp_post_revision_fields( $_POST, true );
1080 $new_autosave['ID'] = $old_autosave->ID;
1081 return wp_update_post( $new_autosave );
1084 // _wp_put_post_revision() expects unescaped.
1085 $_POST = stripslashes_deep($_POST);
1087 // Otherwise create the new autosave as a special post revision
1088 return _wp_put_post_revision( $_POST, true );
1092 * Save draft or manually autosave for showing preview.
1094 * @package WordPress
1097 * @uses wp_write_post()
1100 * @uses current_user_can()
1101 * @uses wp_create_post_autosave()
1103 * @return str URL to redirect to show the preview
1105 function post_preview() {
1107 $post_ID = (int) $_POST['post_ID'];
1109 wp_die( __('Preview not available. Please save as a draft first.') );
1111 if ( isset($_POST['catslist']) )
1112 $_POST['post_category'] = explode(",", $_POST['catslist']);
1114 if ( isset($_POST['tags_input']) )
1115 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1117 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1118 unset($_POST['post_category']);
1120 $_POST['ID'] = $post_ID;
1121 $post = get_post($post_ID);
1123 if ( 'page' == $post->post_type ) {
1124 if ( !current_user_can('edit_page', $post_ID) )
1125 wp_die(__('You are not allowed to edit this page.'));
1127 if ( !current_user_can('edit_post', $post_ID) )
1128 wp_die(__('You are not allowed to edit this post.'));
1131 if ( 'draft' == $post->post_status ) {
1133 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
1134 $id = wp_create_post_autosave( $post->ID );
1135 if ( ! is_wp_error($id) )
1139 if ( is_wp_error($id) )
1140 wp_die( $id->get_error_message() );
1142 if ( $_POST['post_status'] == 'draft' ) {
1143 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1145 $nonce = wp_create_nonce('post_preview_' . $id);
1146 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1153 * Adds the TinyMCE editor used on the Write and Edit screens.
1155 * @package WordPress
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.
1163 * @param bool $teeny optional Output a trimmed down version used in Press This.
1165 function wp_tiny_mce( $teeny = false ) {
1166 global $concatenate_scripts, $compress_scripts, $tinymce_version;
1168 if ( ! user_can_richedit() )
1171 $baseurl = includes_url('js/tinymce');
1173 $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1176 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1177 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1178 The + sign marks the default language. More information:
1179 http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1181 $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');
1184 $plugins = apply_filters( 'teeny_mce_plugins', array('safari', 'inlinepopups', 'media', 'autosave', 'fullscreen') );
1187 $plugins = array( 'safari', 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'media', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus' );
1190 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1191 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1192 The url should be absolute and should include the js file name to be loaded. Example:
1193 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1194 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1196 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1199 if ( ! empty($mce_external_plugins) ) {
1202 The following filter loads external language files for TinyMCE plugins.
1203 It takes an associative array 'plugin_name' => 'path', where path is the
1204 include path to the file. The language file should follow the same format as
1205 /tinymce/langs/wp-langs.php and should define a variable $strings that
1206 holds all translated strings.
1207 When this filter is not used, the function will try to load {mce_locale}.js.
1208 If that is not found, en.js will be tried next.
1210 $mce_external_languages = apply_filters('mce_external_languages', array());
1212 $loaded_langs = array();
1215 if ( ! empty($mce_external_languages) ) {
1216 foreach ( $mce_external_languages as $name => $path ) {
1217 if ( @is_file($path) && @is_readable($path) ) {
1218 include_once($path);
1219 $ext_plugins .= $strings . "\n";
1220 $loaded_langs[] = $name;
1225 foreach ( $mce_external_plugins as $name => $url ) {
1227 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1229 $plugins[] = '-' . $name;
1231 $plugurl = dirname($url);
1232 $strings = $str1 = $str2 = '';
1233 if ( ! in_array($name, $loaded_langs) ) {
1234 $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1235 $path = WP_PLUGIN_DIR . $path . '/langs/';
1237 if ( function_exists('realpath') )
1238 $path = trailingslashit( realpath($path) );
1240 if ( @is_file($path . $mce_locale . '.js') )
1241 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1243 if ( @is_file($path . $mce_locale . '_dlg.js') )
1244 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1246 if ( 'en' != $mce_locale && empty($strings) ) {
1247 if ( @is_file($path . 'en.js') ) {
1248 $str1 = @file_get_contents($path . 'en.js');
1249 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1252 if ( @is_file($path . 'en_dlg.js') ) {
1253 $str2 = @file_get_contents($path . 'en_dlg.js');
1254 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1258 if ( ! empty($strings) )
1259 $ext_plugins .= "\n" . $strings . "\n";
1262 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1263 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1268 $plugins = implode($plugins, ',');
1271 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1272 $mce_buttons = implode($mce_buttons, ',');
1273 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1275 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1276 $mce_buttons = implode($mce_buttons, ',');
1278 $mce_buttons_2 = apply_filters('mce_buttons_2', array('formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'media', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' ));
1279 $mce_buttons_2 = implode($mce_buttons_2, ',');
1281 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1282 $mce_buttons_3 = implode($mce_buttons_3, ',');
1284 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1285 $mce_buttons_4 = implode($mce_buttons_4, ',');
1287 $no_captions = ( apply_filters( 'disable_captions', '' ) ) ? true : false;
1289 // TinyMCE init settings
1290 $initArray = array (
1291 'mode' => 'specific_textareas',
1292 'editor_selector' => 'theEditor',
1294 'theme' => 'advanced',
1295 'skin' => 'wp_theme',
1296 'theme_advanced_buttons1' => "$mce_buttons",
1297 'theme_advanced_buttons2' => "$mce_buttons_2",
1298 'theme_advanced_buttons3' => "$mce_buttons_3",
1299 'theme_advanced_buttons4' => "$mce_buttons_4",
1300 'language' => "$mce_locale",
1301 'spellchecker_languages' => "$mce_spellchecker_languages",
1302 'theme_advanced_toolbar_location' => 'top',
1303 'theme_advanced_toolbar_align' => 'left',
1304 'theme_advanced_statusbar_location' => 'bottom',
1305 'theme_advanced_resizing' => true,
1306 'theme_advanced_resize_horizontal' => false,
1307 'dialog_type' => 'modal',
1308 'relative_urls' => false,
1309 'remove_script_host' => false,
1310 'convert_urls' => false,
1311 'apply_source_formatting' => false,
1312 'remove_linebreaks' => true,
1313 'gecko_spellcheck' => true,
1314 'entities' => '38,amp,60,lt,62,gt',
1315 'accessibility_focus' => true,
1316 'tabfocus_elements' => 'major-publishing-actions',
1317 'media_strict' => false,
1318 'save_callback' => 'switchEditors.saveCallback',
1319 'wpeditimage_disable_captions' => $no_captions,
1320 'plugins' => "$plugins"
1323 $mce_css = trim(apply_filters('mce_css', ''), ' ,');
1325 if ( ! empty($mce_css) )
1326 $initArray['content_css'] = "$mce_css";
1328 // For people who really REALLY know what they're doing with TinyMCE
1329 // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1330 // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1331 // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1333 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1335 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1338 if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1339 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1340 $initArray['theme_advanced_buttons4'] = '';
1343 if ( ! isset($concatenate_scripts) )
1344 script_concat_settings();
1346 $language = $initArray['language'];
1347 $zip = $compress_scripts ? 1 : 0;
1352 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1353 * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1354 * 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).
1356 $version = apply_filters('tiny_mce_version', '');
1357 $version = 'ver=' . $tinymce_version . $version;
1359 if ( 'en' != $language )
1360 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1363 foreach ( $initArray as $k => $v )
1364 $mce_options .= $k . ':"' . $v . '", ';
1366 $mce_options = rtrim( trim($mce_options), '\n\r,' ); ?>
1368 <script type="text/javascript">
1371 base : "<?php echo $baseurl; ?>",
1373 query : "<?php echo $version; ?>",
1374 mceInit : {<?php echo $mce_options; ?>},
1375 load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1381 if ( $concatenate_scripts )
1382 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=$zip&$version'></script>\n";
1384 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1386 if ( 'en' != $language && isset($lang) )
1387 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1389 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1392 <script type="text/javascript">
1394 <?php if ( $ext_plugins ) echo "$ext_plugins\n"; ?>
1395 <?php if ( $concatenate_scripts ) { ?>
1396 tinyMCEPreInit.go();
1398 (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');}});})();
1400 tinyMCE.init(tinyMCEPreInit.mceInit);