Wordpress 3.2
[autoinstalls/wordpress.git] / wp-admin / includes / post.php
1 <?php
2 /**
3  * WordPress Post Administration API.
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * Rename $_POST data from form names to DB post columns.
11  *
12  * Manipulates $_POST directly.
13  *
14  * @package WordPress
15  * @since 2.6.0
16  *
17  * @param bool $update Are we updating a pre-existing post?
18  * @param array $post_data Array of post data. Defaults to the contents of $_POST.
19  * @return object|bool WP_Error on failure, true on success.
20  */
21 function _wp_translate_postdata( $update = false, $post_data = null ) {
22
23         if ( empty($post_data) )
24                 $post_data = &$_POST;
25
26         if ( $update )
27                 $post_data['ID'] = (int) $post_data['post_ID'];
28
29         if ( isset( $post_data['content'] ) )
30                 $post_data['post_content'] = $post_data['content'];
31
32         if ( isset( $post_data['excerpt'] ) )
33                 $post_data['post_excerpt'] = $post_data['excerpt'];
34
35         if ( isset( $post_data['parent_id'] ) )
36                 $post_data['post_parent'] = (int) $post_data['parent_id'];
37
38         if ( isset($post_data['trackback_url']) )
39                 $post_data['to_ping'] = $post_data['trackback_url'];
40
41         if ( !isset($post_data['user_ID']) )
42                 $post_data['user_ID'] = $GLOBALS['user_ID'];
43
44         if (!empty ( $post_data['post_author_override'] ) ) {
45                 $post_data['post_author'] = (int) $post_data['post_author_override'];
46         } else {
47                 if (!empty ( $post_data['post_author'] ) ) {
48                         $post_data['post_author'] = (int) $post_data['post_author'];
49                 } else {
50                         $post_data['post_author'] = (int) $post_data['user_ID'];
51                 }
52         }
53
54         $ptype = get_post_type_object( $post_data['post_type'] );
55         if ( isset($post_data['user_ID']) && ($post_data['post_author'] != $post_data['user_ID']) ) {
56                 if ( !current_user_can( $ptype->cap->edit_others_posts ) ) {
57                         if ( 'page' == $post_data['post_type'] ) {
58                                 return new WP_Error( 'edit_others_pages', $update ?
59                                         __( 'You are not allowed to edit pages as this user.' ) :
60                                         __( 'You are not allowed to create pages as this user.' )
61                                 );
62                         } else {
63                                 return new WP_Error( 'edit_others_posts', $update ?
64                                         __( 'You are not allowed to edit posts as this user.' ) :
65                                         __( 'You are not allowed to post as this user.' )
66                                 );
67                         }
68                 }
69         }
70
71         // What to do based on which button they pressed
72         if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
73                 $post_data['post_status'] = 'draft';
74         if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
75                 $post_data['post_status'] = 'private';
76         if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
77                 $post_data['post_status'] = 'publish';
78         if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
79                 $post_data['post_status'] = 'draft';
80         if ( isset($post_data['pending']) && '' != $post_data['pending'] )
81                 $post_data['post_status'] = 'pending';
82
83         if ( isset( $post_data['ID'] ) )
84                 $post_id = $post_data['ID'];
85         else
86                 $post_id = false;
87         $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
88
89         // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
90         // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
91         if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
92                 if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
93                         $post_data['post_status'] = 'pending';
94
95         if ( ! isset($post_data['post_status']) )
96                 $post_data['post_status'] = $previous_status;
97
98         if (!isset( $post_data['comment_status'] ))
99                 $post_data['comment_status'] = 'closed';
100
101         if (!isset( $post_data['ping_status'] ))
102                 $post_data['ping_status'] = 'closed';
103
104         foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
105                 if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
106                         $post_data['edit_date'] = '1';
107                         break;
108                 }
109         }
110
111         if ( !empty( $post_data['edit_date'] ) ) {
112                 $aa = $post_data['aa'];
113                 $mm = $post_data['mm'];
114                 $jj = $post_data['jj'];
115                 $hh = $post_data['hh'];
116                 $mn = $post_data['mn'];
117                 $ss = $post_data['ss'];
118                 $aa = ($aa <= 0 ) ? date('Y') : $aa;
119                 $mm = ($mm <= 0 ) ? date('n') : $mm;
120                 $jj = ($jj > 31 ) ? 31 : $jj;
121                 $jj = ($jj <= 0 ) ? date('j') : $jj;
122                 $hh = ($hh > 23 ) ? $hh -24 : $hh;
123                 $mn = ($mn > 59 ) ? $mn -60 : $mn;
124                 $ss = ($ss > 59 ) ? $ss -60 : $ss;
125                 $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
126                 $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
127         }
128
129         return $post_data;
130 }
131
132 /**
133  * Update an existing post with values provided in $_POST.
134  *
135  * @since 1.5.0
136  *
137  * @param array $post_data Optional.
138  * @return int Post ID.
139  */
140 function edit_post( $post_data = null ) {
141
142         if ( empty($post_data) )
143                 $post_data = &$_POST;
144
145         // Clear out any data in internal vars.
146         unset( $post_data['filter'] );
147
148         $post_ID = (int) $post_data['post_ID'];
149         $post = get_post( $post_ID );
150         $post_data['post_type'] = $post->post_type;
151         $post_data['post_mime_type'] = $post->post_mime_type;
152
153         $ptype = get_post_type_object($post_data['post_type']);
154         if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
155                 if ( 'page' == $post_data['post_type'] )
156                         wp_die( __('You are not allowed to edit this page.' ));
157                 else
158                         wp_die( __('You are not allowed to edit this post.' ));
159         }
160
161         // Autosave shouldn't save too soon after a real save
162         if ( 'autosave' == $post_data['action'] ) {
163                 $post =& get_post( $post_ID );
164                 $now = time();
165                 $then = strtotime($post->post_date_gmt . ' +0000');
166                 $delta = AUTOSAVE_INTERVAL / 2;
167                 if ( ($now - $then) < $delta )
168                         return $post_ID;
169         }
170
171         $post_data = _wp_translate_postdata( true, $post_data );
172         if ( is_wp_error($post_data) )
173                 wp_die( $post_data->get_error_message() );
174         if ( 'autosave' != $post_data['action']  && 'auto-draft' == $post_data['post_status'] )
175                 $post_data['post_status'] = 'draft';
176
177         if ( isset($post_data['visibility']) ) {
178                 switch ( $post_data['visibility'] ) {
179                         case 'public' :
180                                 $post_data['post_password'] = '';
181                                 break;
182                         case 'password' :
183                                 unset( $post_data['sticky'] );
184                                 break;
185                         case 'private' :
186                                 $post_data['post_status'] = 'private';
187                                 $post_data['post_password'] = '';
188                                 unset( $post_data['sticky'] );
189                                 break;
190                 }
191         }
192
193         // Post Formats
194         if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) {
195                 $formats = get_theme_support( 'post-formats' );
196                 if ( is_array( $formats ) ) {
197                         $formats = $formats[0];
198                         if ( in_array( $post_data['post_format'], $formats ) ) {
199                                 set_post_format( $post_ID, $post_data['post_format'] );
200                         } elseif ( '0' == $post_data['post_format'] ) {
201                                 set_post_format( $post_ID, false );
202                         }
203                 }
204         }
205
206         // Meta Stuff
207         if ( isset($post_data['meta']) && $post_data['meta'] ) {
208                 foreach ( $post_data['meta'] as $key => $value ) {
209                         if ( !$meta = get_post_meta_by_id( $key ) )
210                                 continue;
211                         if ( $meta->post_id != $post_ID )
212                                 continue;
213                         if ( is_protected_meta( $value['key'] ) )
214                                 continue;
215                         update_meta( $key, $value['key'], $value['value'] );
216                 }
217         }
218
219         if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
220                 foreach ( $post_data['deletemeta'] as $key => $value ) {
221                         if ( !$meta = get_post_meta_by_id( $key ) )
222                                 continue;
223                         if ( $meta->post_id != $post_ID )
224                                 continue;
225                         if ( is_protected_meta( $meta->meta_key ) )
226                                 continue;
227                         delete_meta( $key );
228                 }
229         }
230
231         add_meta( $post_ID );
232
233         update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
234
235         wp_update_post( $post_data );
236
237         // Reunite any orphaned attachments with their parent
238         if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
239                 $draft_ids = array();
240         if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
241                 _relocate_children( $draft_temp_id, $post_ID );
242
243         // Now that we have an ID we can fix any attachment anchor hrefs
244         _fix_attachment_links( $post_ID );
245
246         wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
247
248         if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
249                 if ( ! empty( $post_data['sticky'] ) )
250                         stick_post( $post_ID );
251                 else
252                         unstick_post( $post_ID );
253         }
254
255         return $post_ID;
256 }
257
258 /**
259  * Process the post data for the bulk editing of posts.
260  *
261  * Updates all bulk edited posts/pages, adding (but not removing) tags and
262  * categories. Skips pages when they would be their own parent or child.
263  *
264  * @since 2.7.0
265  *
266  * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
267  * @return array
268  */
269 function bulk_edit_posts( $post_data = null ) {
270         global $wpdb;
271
272         if ( empty($post_data) )
273                 $post_data = &$_POST;
274
275         if ( isset($post_data['post_type']) )
276                 $ptype = get_post_type_object($post_data['post_type']);
277         else
278                 $ptype = get_post_type_object('post');
279
280         if ( !current_user_can( $ptype->cap->edit_posts ) ) {
281                 if ( 'page' == $ptype->name )
282                         wp_die( __('You are not allowed to edit pages.'));
283                 else
284                         wp_die( __('You are not allowed to edit posts.'));
285         }
286
287         if ( -1 == $post_data['_status'] ) {
288                 $post_data['post_status'] = null;
289                 unset($post_data['post_status']);
290         } else {
291                 $post_data['post_status'] = $post_data['_status'];
292         }
293         unset($post_data['_status']);
294
295         $post_IDs = array_map( 'intval', (array) $post_data['post'] );
296
297         $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
298         foreach ( $reset as $field ) {
299                 if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
300                         unset($post_data[$field]);
301         }
302
303         if ( isset($post_data['post_category']) ) {
304                 if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
305                         $new_cats = array_map( 'absint', $post_data['post_category'] );
306                 else
307                         unset($post_data['post_category']);
308         }
309
310         $tax_input = array();
311         if ( isset($post_data['tax_input'])) {
312                 foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
313                         if ( empty($terms) )
314                                 continue;
315                         if ( is_taxonomy_hierarchical( $tax_name ) )
316                                 $tax_input[$tax_name] = array_map( 'absint', $terms );
317                         else {
318                                 $tax_input[$tax_name] = preg_replace( '/\s*,\s*/', ',', rtrim( trim($terms), ' ,' ) );
319                                 $tax_input[$tax_name] = explode(',', $tax_input[$tax_name]);
320                         }
321                 }
322         }
323
324         if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
325                 $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
326                 $children = array();
327
328                 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
329                         $children[] = $parent;
330
331                         foreach ( $pages as $page ) {
332                                 if ( $page->ID == $parent ) {
333                                         $parent = $page->post_parent;
334                                         break;
335                                 }
336                         }
337                 }
338         }
339
340         $updated = $skipped = $locked = array();
341         foreach ( $post_IDs as $post_ID ) {
342                 $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
343
344                 if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
345                         $skipped[] = $post_ID;
346                         continue;
347                 }
348
349                 if ( wp_check_post_lock( $post_ID ) ) {
350                         $locked[] = $post_ID;
351                         continue;
352                 }
353
354                 $post = get_post( $post_ID );
355                 $tax_names = get_object_taxonomies( $post );
356                 foreach ( $tax_names as $tax_name ) {
357                         $taxonomy_obj = get_taxonomy($tax_name);
358                         if (  isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
359                                 $new_terms = $tax_input[$tax_name];
360                         else
361                                 $new_terms = array();
362
363                         if ( $taxonomy_obj->hierarchical )
364                                 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
365                         else
366                                 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
367
368                         $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
369                 }
370
371                 if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
372                         $cats = (array) wp_get_post_categories($post_ID);
373                         $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
374                         unset( $post_data['tax_input']['category'] );
375                 }
376
377                 $post_data['post_mime_type'] = $post->post_mime_type;
378                 $post_data['guid'] = $post->guid;
379
380                 $post_data['ID'] = $post_ID;
381                 $updated[] = wp_update_post( $post_data );
382
383                 if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
384                         if ( 'sticky' == $post_data['sticky'] )
385                                 stick_post( $post_ID );
386                         else
387                                 unstick_post( $post_ID );
388                 }
389
390         }
391
392         return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
393 }
394
395 /**
396  * Default post information to use when populating the "Write Post" form.
397  *
398  * @since 2.0.0
399  *
400  * @param string $post_type A post type string, defaults to 'post'.
401  * @return object stdClass object containing all the default post data as attributes
402  */
403 function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
404         global $wpdb;
405
406         $post_title = '';
407         if ( !empty( $_REQUEST['post_title'] ) )
408                 $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
409
410         $post_content = '';
411         if ( !empty( $_REQUEST['content'] ) )
412                 $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
413
414         $post_excerpt = '';
415         if ( !empty( $_REQUEST['excerpt'] ) )
416                 $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
417
418         if ( $create_in_db ) {
419                 // Cleanup old auto-drafts more than 7 days old
420                 $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
421                 foreach ( (array) $old_posts as $delete )
422                         wp_delete_post( $delete, true ); // Force delete
423                 $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
424                 $post = get_post( $post_id );
425                 if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
426                         set_post_format( $post, get_option( 'default_post_format' ) );
427         } else {
428                 $post->ID = 0;
429                 $post->post_author = '';
430                 $post->post_date = '';
431                 $post->post_date_gmt = '';
432                 $post->post_password = '';
433                 $post->post_type = $post_type;
434                 $post->post_status = 'draft';
435                 $post->to_ping = '';
436                 $post->pinged = '';
437                 $post->comment_status = get_option( 'default_comment_status' );
438                 $post->ping_status = get_option( 'default_ping_status' );
439                 $post->post_pingback = get_option( 'default_pingback_flag' );
440                 $post->post_category = get_option( 'default_category' );
441                 $post->page_template = 'default';
442                 $post->post_parent = 0;
443                 $post->menu_order = 0;
444         }
445
446         $post->post_content = apply_filters( 'default_content', $post_content, $post );
447         $post->post_title   = apply_filters( 'default_title',   $post_title, $post   );
448         $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
449         $post->post_name = '';
450
451         return $post;
452 }
453
454 /**
455  * Get the default page information to use.
456  *
457  * @since 2.5.0
458  *
459  * @return object stdClass object containing all the default post data as attributes
460  */
461 function get_default_page_to_edit() {
462         $page = get_default_post_to_edit();
463         $page->post_type = 'page';
464         return $page;
465 }
466
467 /**
468  * Get an existing post and format it for editing.
469  *
470  * @since 2.0.0
471  *
472  * @param unknown_type $id
473  * @return unknown
474  */
475 function get_post_to_edit( $id ) {
476
477         $post = get_post( $id, OBJECT, 'edit' );
478
479         if ( $post->post_type == 'page' )
480                 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
481
482         return $post;
483 }
484
485 /**
486  * Determine if a post exists based on title, content, and date
487  *
488  * @since 2.0.0
489  *
490  * @param string $title Post title
491  * @param string $content Optional post content
492  * @param string $date Optional post date
493  * @return int Post ID if post exists, 0 otherwise.
494  */
495 function post_exists($title, $content = '', $date = '') {
496         global $wpdb;
497
498         $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
499         $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
500         $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
501
502         $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
503         $args = array();
504
505         if ( !empty ( $date ) ) {
506                 $query .= ' AND post_date = %s';
507                 $args[] = $post_date;
508         }
509
510         if ( !empty ( $title ) ) {
511                 $query .= ' AND post_title = %s';
512                 $args[] = $post_title;
513         }
514
515         if ( !empty ( $content ) ) {
516                 $query .= 'AND post_content = %s';
517                 $args[] = $post_content;
518         }
519
520         if ( !empty ( $args ) )
521                 return $wpdb->get_var( $wpdb->prepare($query, $args) );
522
523         return 0;
524 }
525
526 /**
527  * Creates a new post from the "Write Post" form using $_POST information.
528  *
529  * @since 2.1.0
530  *
531  * @return unknown
532  */
533 function wp_write_post() {
534         global $user_ID;
535
536
537         if ( isset($_POST['post_type']) )
538                 $ptype = get_post_type_object($_POST['post_type']);
539         else
540                 $ptype = get_post_type_object('post');
541
542         if ( !current_user_can( $ptype->cap->edit_posts ) ) {
543                 if ( 'page' == $ptype->name )
544                         return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
545                 else
546                         return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
547         }
548
549         $_POST['post_mime_type'] = '';
550
551         // Clear out any data in internal vars.
552         unset( $_POST['filter'] );
553
554         // Check for autosave collisions
555         // Does this need to be updated? ~ Mark
556         $temp_id = false;
557         if ( isset($_POST['temp_ID']) ) {
558                 $temp_id = (int) $_POST['temp_ID'];
559                 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
560                         $draft_ids = array();
561                 foreach ( $draft_ids as $temp => $real )
562                         if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
563                                 unset($draft_ids[$temp]);
564
565                 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
566                         $_POST['post_ID'] = $draft_ids[$temp_id];
567                         unset($_POST['temp_ID']);
568                         update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
569                         return edit_post();
570                 }
571         }
572
573         // Edit don't write if we have a post id.
574         if ( isset( $_POST['ID'] ) ) {
575                 $_POST['post_ID'] = $_POST['ID'];
576                 unset ( $_POST['ID'] );
577         }
578         if ( isset( $_POST['post_ID'] ) ) {
579                 return edit_post();
580         }
581
582         $translated = _wp_translate_postdata( false );
583         if ( is_wp_error($translated) )
584                 return $translated;
585
586         if ( isset($_POST['visibility']) ) {
587                 switch ( $_POST['visibility'] ) {
588                         case 'public' :
589                                 $_POST['post_password'] = '';
590                                 break;
591                         case 'password' :
592                                 unset( $_POST['sticky'] );
593                                 break;
594                         case 'private' :
595                                 $_POST['post_status'] = 'private';
596                                 $_POST['post_password'] = '';
597                                 unset( $_POST['sticky'] );
598                                 break;
599                 }
600         }
601
602         // Create the post.
603         $post_ID = wp_insert_post( $_POST );
604         if ( is_wp_error( $post_ID ) )
605                 return $post_ID;
606
607         if ( empty($post_ID) )
608                 return 0;
609
610         add_meta( $post_ID );
611
612         add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
613
614         // Reunite any orphaned attachments with their parent
615         // Does this need to be udpated? ~ Mark
616         if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
617                 $draft_ids = array();
618         if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
619                 _relocate_children( $draft_temp_id, $post_ID );
620         if ( $temp_id && $temp_id != $draft_temp_id )
621                 _relocate_children( $temp_id, $post_ID );
622
623         // Update autosave collision detection
624         if ( $temp_id ) {
625                 $draft_ids[$temp_id] = $post_ID;
626                 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
627         }
628
629         // Now that we have an ID we can fix any attachment anchor hrefs
630         _fix_attachment_links( $post_ID );
631
632         wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
633
634         return $post_ID;
635 }
636
637 /**
638  * Calls wp_write_post() and handles the errors.
639  *
640  * @since 2.0.0
641  *
642  * @return unknown
643  */
644 function write_post() {
645         $result = wp_write_post();
646         if ( is_wp_error( $result ) )
647                 wp_die( $result->get_error_message() );
648         else
649                 return $result;
650 }
651
652 //
653 // Post Meta
654 //
655
656 /**
657  * {@internal Missing Short Description}}
658  *
659  * @since 1.2.0
660  *
661  * @param unknown_type $post_ID
662  * @return unknown
663  */
664 function add_meta( $post_ID ) {
665         global $wpdb;
666         $post_ID = (int) $post_ID;
667
668         $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
669         $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
670         $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes_deep( $_POST['metavalue'] ) ) : '';
671         if ( is_string($metavalue) )
672                 $metavalue = trim( $metavalue );
673
674         if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
675                 // We have a key/value pair. If both the select and the
676                 // input for the key have data, the input takes precedence:
677
678                 if ('#NONE#' != $metakeyselect)
679                         $metakey = $metakeyselect;
680
681                 if ( $metakeyinput)
682                         $metakey = $metakeyinput; // default
683
684                 if ( is_protected_meta( $metakey ) )
685                         return false;
686
687                 wp_cache_delete($post_ID, 'post_meta');
688                 $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) );
689                 $meta_id = $wpdb->insert_id;
690                 do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue );
691
692                 return $meta_id;
693         }
694         return false;
695 } // add_meta
696
697 /**
698  * {@internal Missing Short Description}}
699  *
700  * @since 1.2.0
701  *
702  * @param unknown_type $mid
703  * @return unknown
704  */
705 function delete_meta( $mid ) {
706         global $wpdb;
707         $mid = (int) $mid;
708
709         $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
710
711         do_action( 'delete_postmeta', $mid );
712         wp_cache_delete($post_id, 'post_meta');
713         $rval = $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
714         do_action( 'deleted_postmeta', $mid );
715
716         return $rval;
717 }
718
719 /**
720  * Get a list of previously defined keys.
721  *
722  * @since 1.2.0
723  *
724  * @return unknown
725  */
726 function get_meta_keys() {
727         global $wpdb;
728
729         $keys = $wpdb->get_col( "
730                         SELECT meta_key
731                         FROM $wpdb->postmeta
732                         GROUP BY meta_key
733                         ORDER BY meta_key" );
734
735         return $keys;
736 }
737
738 /**
739  * {@internal Missing Short Description}}
740  *
741  * @since 2.1.0
742  *
743  * @param unknown_type $mid
744  * @return unknown
745  */
746 function get_post_meta_by_id( $mid ) {
747         global $wpdb;
748         $mid = (int) $mid;
749
750         $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
751         if ( empty($meta) )
752                 return false;
753         if ( is_serialized_string( $meta->meta_value ) )
754                 $meta->meta_value = maybe_unserialize( $meta->meta_value );
755         return $meta;
756 }
757
758 /**
759  * {@internal Missing Short Description}}
760  *
761  * Some postmeta stuff.
762  *
763  * @since 1.2.0
764  *
765  * @param unknown_type $postid
766  * @return unknown
767  */
768 function has_meta( $postid ) {
769         global $wpdb;
770
771         return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
772                         FROM $wpdb->postmeta WHERE post_id = %d
773                         ORDER BY meta_key,meta_id", $postid), ARRAY_A );
774
775 }
776
777 /**
778  * {@internal Missing Short Description}}
779  *
780  * @since 1.2.0
781  *
782  * @param unknown_type $meta_id
783  * @param unknown_type $meta_key Expect Slashed
784  * @param unknown_type $meta_value Expect Slashed
785  * @return unknown
786  */
787 function update_meta( $meta_id, $meta_key, $meta_value ) {
788         global $wpdb;
789
790         $meta_key = stripslashes($meta_key);
791
792         if ( is_protected_meta( $meta_key ) )
793                 return false;
794
795         if ( '' === trim( $meta_value ) )
796                 return false;
797
798         $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
799
800         $meta_value = maybe_serialize( stripslashes_deep( $meta_value ) );
801         $meta_id = (int) $meta_id;
802
803         $data  = compact( 'meta_key', 'meta_value' );
804         $where = compact( 'meta_id' );
805
806         do_action( 'update_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
807         $rval = $wpdb->update( $wpdb->postmeta, $data, $where );
808         wp_cache_delete($post_id, 'post_meta');
809         do_action( 'updated_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
810
811         return $rval;
812 }
813
814 //
815 // Private
816 //
817
818 /**
819  * Replace hrefs of attachment anchors with up-to-date permalinks.
820  *
821  * @since 2.3.0
822  * @access private
823  *
824  * @param unknown_type $post_ID
825  * @return unknown
826  */
827 function _fix_attachment_links( $post_ID ) {
828         global $_fix_attachment_link_id;
829
830         $post = & get_post( $post_ID, ARRAY_A );
831
832         $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
833
834         // See if we have any rel="attachment" links
835         if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
836                 return;
837
838         $i = 0;
839         $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
840         foreach ( $anchor_matches[0] as $anchor ) {
841                 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
842                         continue;
843
844                 $id = (int) $id_matches[3];
845
846                 // While we have the attachment ID, let's adopt any orphans.
847                 $attachment = & get_post( $id, ARRAY_A );
848                 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
849                         $attachment['post_parent'] = $post_ID;
850                         // Escape data pulled from DB.
851                         $attachment = add_magic_quotes( $attachment );
852                         wp_update_post( $attachment );
853                 }
854
855                 $post_search[$i] = $anchor;
856                  $_fix_attachment_link_id = $id;
857                 $post_replace[$i] = preg_replace_callback( "#href=(\"|')[^'\"]*\\1#", '_fix_attachment_links_replace_cb', $anchor );
858                 ++$i;
859         }
860
861         $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
862
863         // Escape data pulled from DB.
864         $post = add_magic_quotes( $post);
865
866         return wp_update_post( $post);
867 }
868
869 function _fix_attachment_links_replace_cb($match) {
870         global $_fix_attachment_link_id;
871         return stripslashes( 'href='.$match[1] ).get_attachment_link( $_fix_attachment_link_id ).stripslashes( $match[1] );
872 }
873
874 /**
875  * Move child posts to a new parent.
876  *
877  * @since 2.3.0
878  * @access private
879  *
880  * @param unknown_type $old_ID
881  * @param unknown_type $new_ID
882  * @return unknown
883  */
884 function _relocate_children( $old_ID, $new_ID ) {
885         global $wpdb;
886         $old_ID = (int) $old_ID;
887         $new_ID = (int) $new_ID;
888
889         $children = $wpdb->get_col( $wpdb->prepare("
890                 SELECT post_id
891                 FROM $wpdb->postmeta
892                 WHERE meta_key = '_wp_attachment_temp_parent'
893                 AND meta_value = %d", $old_ID) );
894
895         foreach ( $children as $child_id ) {
896                 $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
897                 delete_post_meta($child_id, '_wp_attachment_temp_parent');
898         }
899 }
900
901 /**
902  * Get all the possible statuses for a post_type
903  *
904  * @since 2.5.0
905  *
906  * @param string $type The post_type you want the statuses for
907  * @return array As array of all the statuses for the supplied post type
908  */
909 function get_available_post_statuses($type = 'post') {
910         $stati = wp_count_posts($type);
911
912         return array_keys(get_object_vars($stati));
913 }
914
915 /**
916  * Run the wp query to fetch the posts for listing on the edit posts page
917  *
918  * @since 2.5.0
919  *
920  * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
921  * @return array
922  */
923 function wp_edit_posts_query( $q = false ) {
924         if ( false === $q )
925                 $q = $_GET;
926         $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
927         $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
928         $post_stati  = get_post_stati();
929
930         if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
931                 $post_type = $q['post_type'];
932         else
933                 $post_type = 'post';
934
935         $avail_post_stati = get_available_post_statuses($post_type);
936
937         if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
938                 $post_status = $q['post_status'];
939                 $perm = 'readable';
940         }
941
942         if ( isset($q['orderby']) )
943                 $orderby = $q['orderby'];
944         elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
945                 $orderby = 'modified';
946
947         if ( isset($q['order']) )
948                 $order = $q['order'];
949         elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
950                 $order = 'ASC';
951
952         $per_page = 'edit_' . $post_type . '_per_page';
953         $posts_per_page = (int) get_user_option( $per_page );
954         if ( empty( $posts_per_page ) || $posts_per_page < 1 )
955                 $posts_per_page = 20;
956
957         $posts_per_page = apply_filters( $per_page, $posts_per_page );
958         $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
959
960         $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
961
962         // Hierarchical types require special args.
963         if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
964                 $query['orderby'] = 'menu_order title';
965                 $query['order'] = 'asc';
966                 $query['posts_per_page'] = -1;
967                 $query['posts_per_archive_page'] = -1;
968         }
969
970         if ( ! empty( $q['show_sticky'] ) )
971                 $query['post__in'] = (array) get_option( 'sticky_posts' );
972
973         wp( $query );
974
975         return $avail_post_stati;
976 }
977
978 /**
979  * Get default post mime types
980  *
981  * @since 2.9.0
982  *
983  * @return array
984  */
985 function get_post_mime_types() {
986         $post_mime_types = array(       //      array( adj, noun )
987                 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
988                 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
989                 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
990         );
991
992         return apply_filters('post_mime_types', $post_mime_types);
993 }
994
995 /**
996  * {@internal Missing Short Description}}
997  *
998  * @since 2.5.0
999  *
1000  * @param unknown_type $type
1001  * @return unknown
1002  */
1003 function get_available_post_mime_types($type = 'attachment') {
1004         global $wpdb;
1005
1006         $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
1007         return $types;
1008 }
1009
1010 /**
1011  * {@internal Missing Short Description}}
1012  *
1013  * @since 2.5.0
1014  *
1015  * @param unknown_type $q
1016  * @return unknown
1017  */
1018 function wp_edit_attachments_query( $q = false ) {
1019         if ( false === $q )
1020                 $q = $_GET;
1021
1022         $q['m']   = isset( $q['m'] ) ? (int) $q['m'] : 0;
1023         $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
1024         $q['post_type'] = 'attachment';
1025         $post_type = get_post_type_object( 'attachment' );
1026         $states = 'inherit';
1027         if ( current_user_can( $post_type->cap->read_private_posts ) )
1028                 $states .= ',private';
1029
1030         $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
1031         $media_per_page = (int) get_user_option( 'upload_per_page' );
1032         if ( empty( $media_per_page ) || $media_per_page < 1 )
1033                 $media_per_page = 20;
1034         $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
1035
1036         $post_mime_types = get_post_mime_types();
1037         $avail_post_mime_types = get_available_post_mime_types('attachment');
1038
1039         if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
1040                 unset($q['post_mime_type']);
1041
1042         if ( isset($q['detached']) )
1043                 add_filter('posts_where', '_edit_attachments_query_helper');
1044
1045         wp( $q );
1046
1047         if ( isset($q['detached']) )
1048                 remove_filter('posts_where', '_edit_attachments_query_helper');
1049
1050         return array($post_mime_types, $avail_post_mime_types);
1051 }
1052
1053 function _edit_attachments_query_helper($where) {
1054         return $where .= ' AND post_parent < 1';
1055 }
1056
1057 /**
1058  * Returns the list of classes to be used by a metabox
1059  *
1060  * @uses get_user_option()
1061  * @since 2.5.0
1062  *
1063  * @param unknown_type $id
1064  * @param unknown_type $page
1065  * @return unknown
1066  */
1067 function postbox_classes( $id, $page ) {
1068         if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id ) {
1069                 $classes = array( '' );
1070         } elseif ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
1071                 if ( !is_array( $closed ) ) {
1072                         $classes = array( '' );
1073                 } else {
1074                         $classes = in_array( $id, $closed ) ? array( 'closed' ) : array( '' );
1075                 }
1076         } else {
1077                 $classes = array( '' );
1078         }
1079
1080         $classes = apply_filters( "postbox_classes_{$page}_{$id}", $classes );
1081         return implode( ' ', $classes );
1082 }
1083
1084 /**
1085  * {@internal Missing Short Description}}
1086  *
1087  * @since 2.5.0
1088  *
1089  * @param int|object $id    Post ID or post object.
1090  * @param string $title (optional) Title
1091  * @param string $name (optional) Name
1092  * @return array With two entries of type string
1093  */
1094 function get_sample_permalink($id, $title = null, $name = null) {
1095         $post = &get_post($id);
1096         if ( !$post->ID )
1097                 return array('', '');
1098
1099         $ptype = get_post_type_object($post->post_type);
1100
1101         $original_status = $post->post_status;
1102         $original_date = $post->post_date;
1103         $original_name = $post->post_name;
1104
1105         // Hack: get_permalink would return ugly permalink for
1106         // drafts, so we will fake, that our post is published
1107         if ( in_array($post->post_status, array('draft', 'pending')) ) {
1108                 $post->post_status = 'publish';
1109                 $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
1110         }
1111
1112         // If the user wants to set a new name -- override the current one
1113         // Note: if empty name is supplied -- use the title instead, see #6072
1114         if ( !is_null($name) )
1115                 $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
1116
1117         $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
1118
1119         $post->filter = 'sample';
1120
1121         $permalink = get_permalink($post, true);
1122
1123         // Replace custom post_type Token with generic pagename token for ease of use.
1124         $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
1125
1126         // Handle page hierarchy
1127         if ( $ptype->hierarchical ) {
1128                 $uri = get_page_uri($post);
1129                 $uri = untrailingslashit($uri);
1130                 $uri = strrev( stristr( strrev( $uri ), '/' ) );
1131                 $uri = untrailingslashit($uri);
1132                 $uri = apply_filters( 'editable_slug', $uri );
1133                 if ( !empty($uri) )
1134                         $uri .= '/';
1135                 $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
1136         }
1137
1138         $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
1139         $post->post_status = $original_status;
1140         $post->post_date = $original_date;
1141         $post->post_name = $original_name;
1142         unset($post->filter);
1143
1144         return $permalink;
1145 }
1146
1147 /**
1148  * sample permalink html
1149  *
1150  * intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1151  *
1152  * @since 2.5.0
1153  *
1154  * @param int|object $id Post ID or post object.
1155  * @param string $new_title (optional) New title
1156  * @param string $new_slug (optional) New slug
1157  * @return string intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1158  */
1159 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
1160         global $wpdb;
1161         $post = &get_post($id);
1162
1163         list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
1164
1165         if ( 'publish' == $post->post_status ) {
1166                 $ptype = get_post_type_object($post->post_type);
1167                 $view_post = $ptype->labels->view_item;
1168                 $title = __('Click to edit this part of the permalink');
1169         } else {
1170                 $title = __('Temporary permalink. Click to edit this part.');
1171         }
1172
1173         if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
1174                 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
1175                 if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
1176                         $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
1177                 if ( isset($view_post) )
1178                         $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
1179
1180                 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1181
1182                 return $return;
1183         }
1184
1185         if ( function_exists('mb_strlen') ) {
1186                 if ( mb_strlen($post_name) > 30 ) {
1187                         $post_name_abridged = mb_substr($post_name, 0, 14). '&hellip;' . mb_substr($post_name, -14);
1188                 } else {
1189                         $post_name_abridged = $post_name;
1190                 }
1191         } else {
1192                 if ( strlen($post_name) > 30 ) {
1193                         $post_name_abridged = substr($post_name, 0, 14). '&hellip;' . substr($post_name, -14);
1194                 } else {
1195                         $post_name_abridged = $post_name;
1196                 }
1197         }
1198
1199         $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
1200         $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
1201         $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
1202         $return =  '<strong>' . __('Permalink:') . "</strong>\n";
1203         $return .= '<span id="sample-permalink">' . $display_link . "</span>\n";
1204         $return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
1205         $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";
1206         $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
1207         if ( isset($view_post) )
1208                 $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
1209
1210         $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1211
1212         return $return;
1213 }
1214
1215 /**
1216  * Output HTML for the post thumbnail meta-box.
1217  *
1218  * @since 2.9.0
1219  *
1220  * @param int $thumbnail_id ID of the attachment used for thumbnail
1221  * @return string html
1222  */
1223 function _wp_post_thumbnail_html( $thumbnail_id = NULL ) {
1224         global $content_width, $_wp_additional_image_sizes, $post_ID;
1225         $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>';
1226         $content = sprintf($set_thumbnail_link, esc_html__( 'Set featured image' ));
1227
1228         if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
1229                 $old_content_width = $content_width;
1230                 $content_width = 266;
1231                 if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
1232                         $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
1233                 else
1234                         $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
1235                 if ( !empty( $thumbnail_html ) ) {
1236                         $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" );
1237                         $content = sprintf($set_thumbnail_link, $thumbnail_html);
1238                         $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>';
1239                 }
1240                 $content_width = $old_content_width;
1241         }
1242
1243         return apply_filters( 'admin_post_thumbnail_html', $content );
1244 }
1245
1246 /**
1247  * Check to see if the post is currently being edited by another user.
1248  *
1249  * @since 2.5.0
1250  *
1251  * @param int $post_id ID of the post to check for editing
1252  * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
1253  */
1254 function wp_check_post_lock( $post_id ) {
1255         if ( !$post = get_post( $post_id ) )
1256                 return false;
1257
1258         if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
1259                 return false;
1260
1261         $lock = explode( ':', $lock );
1262         $time = $lock[0];
1263         $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1264
1265         $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
1266
1267         if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
1268                 return $user;
1269         return false;
1270 }
1271
1272 /**
1273  * Mark the post as currently being edited by the current user
1274  *
1275  * @since 2.5.0
1276  *
1277  * @param int $post_id ID of the post to being edited
1278  * @return bool Returns false if the post doesn't exist of there is no current user
1279  */
1280 function wp_set_post_lock( $post_id ) {
1281         if ( !$post = get_post( $post_id ) )
1282                 return false;
1283         if ( 0 == ($user_id = get_current_user_id()) )
1284                 return false;
1285
1286         $now = time();
1287         $lock = "$now:$user_id";
1288
1289         update_post_meta( $post->ID, '_edit_lock', $lock );
1290 }
1291
1292 /**
1293  * Outputs the notice message to say that someone else is editing this post at the moment.
1294  *
1295  * @since 2.8.5
1296  * @return none
1297  */
1298 function _admin_notice_post_locked() {
1299         global $post;
1300
1301         $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
1302         $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1303         $last_user = get_userdata( $user );
1304         $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
1305
1306         switch ($post->post_type) {
1307                 case 'post':
1308                         $message = __( 'Warning: %s is currently editing this post' );
1309                         break;
1310                 case 'page':
1311                         $message = __( 'Warning: %s is currently editing this page' );
1312                         break;
1313                 default:
1314                         $message = __( 'Warning: %s is currently editing this.' );
1315         }
1316
1317         $message = sprintf( $message, esc_html( $last_user_name ) );
1318         echo "<div class='error'><p>$message</p></div>";
1319 }
1320
1321 /**
1322  * Creates autosave data for the specified post from $_POST data.
1323  *
1324  * @package WordPress
1325  * @subpackage Post_Revisions
1326  * @since 2.6.0
1327  *
1328  * @uses _wp_translate_postdata()
1329  * @uses _wp_post_revision_fields()
1330  *
1331  * @return unknown
1332  */
1333 function wp_create_post_autosave( $post_id ) {
1334         $translated = _wp_translate_postdata( true );
1335         if ( is_wp_error( $translated ) )
1336                 return $translated;
1337
1338         // Only store one autosave.  If there is already an autosave, overwrite it.
1339         if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1340                 $new_autosave = _wp_post_revision_fields( $_POST, true );
1341                 $new_autosave['ID'] = $old_autosave->ID;
1342                 $new_autosave['post_author'] = get_current_user_id();
1343                 return wp_update_post( $new_autosave );
1344         }
1345
1346         // _wp_put_post_revision() expects unescaped.
1347         $_POST = stripslashes_deep($_POST);
1348
1349         // Otherwise create the new autosave as a special post revision
1350         return _wp_put_post_revision( $_POST, true );
1351 }
1352
1353 /**
1354  * Save draft or manually autosave for showing preview.
1355  *
1356  * @package WordPress
1357  * @since 2.7.0
1358  *
1359  * @uses wp_write_post()
1360  * @uses edit_post()
1361  * @uses get_post()
1362  * @uses current_user_can()
1363  * @uses wp_create_post_autosave()
1364  *
1365  * @return str URL to redirect to show the preview
1366  */
1367 function post_preview() {
1368
1369         $post_ID = (int) $_POST['post_ID'];
1370         $status = get_post_status( $post_ID );
1371         if ( 'auto-draft' == $status )
1372                 wp_die( __('Preview not available. Please save as a draft first.') );
1373
1374         if ( isset($_POST['catslist']) )
1375                 $_POST['post_category'] = explode(",", $_POST['catslist']);
1376
1377         if ( isset($_POST['tags_input']) )
1378                 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1379
1380         if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1381                 unset($_POST['post_category']);
1382
1383         $_POST['ID'] = $post_ID;
1384         $post = get_post($post_ID);
1385
1386         if ( 'page' == $post->post_type ) {
1387                 if ( !current_user_can('edit_page', $post_ID) )
1388                         wp_die(__('You are not allowed to edit this page.'));
1389         } else {
1390                 if ( !current_user_can('edit_post', $post_ID) )
1391                         wp_die(__('You are not allowed to edit this post.'));
1392         }
1393
1394         if ( 'draft' == $post->post_status ) {
1395                 $id = edit_post();
1396         } else { // Non drafts are not overwritten.  The autosave is stored in a special post revision.
1397                 $id = wp_create_post_autosave( $post->ID );
1398                 if ( ! is_wp_error($id) )
1399                         $id = $post->ID;
1400         }
1401
1402         if ( is_wp_error($id) )
1403                 wp_die( $id->get_error_message() );
1404
1405         if ( $_POST['post_status'] == 'draft'  ) {
1406                 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1407         } else {
1408                 $nonce = wp_create_nonce('post_preview_' . $id);
1409                 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1410         }
1411
1412         return $url;
1413 }
1414
1415 /**
1416  * Adds the TinyMCE editor used on the Write and Edit screens.
1417  *
1418  * @package WordPress
1419  * @since 2.7.0
1420  *
1421  * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
1422  * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
1423  * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
1424  * to the URL when queueing them with the mce_external_plugins filter.
1425  *
1426  * @param bool $teeny optional Output a trimmed down version used in Press This.
1427  * @param mixed $settings optional An array that can add to or overwrite the default TinyMCE settings.
1428  */
1429 function wp_tiny_mce( $teeny = false, $settings = false ) {
1430         global $concatenate_scripts, $compress_scripts, $tinymce_version, $editor_styles;
1431
1432         if ( ! user_can_richedit() )
1433                 return;
1434
1435         $baseurl = includes_url('js/tinymce');
1436
1437         $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1438
1439         /*
1440         The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1441         By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1442         The + sign marks the default language. More information:
1443         http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1444         */
1445         $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');
1446
1447         if ( $teeny ) {
1448                 $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs') );
1449                 $ext_plugins = '';
1450         } else {
1451                 $plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'wordpress', 'wpfullscreen', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
1452
1453                 /*
1454                 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1455                 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1456                 The url should be absolute and should include the js file name to be loaded. Example:
1457                 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1458                 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1459                 */
1460                 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1461
1462                 $ext_plugins = '';
1463                 if ( ! empty($mce_external_plugins) ) {
1464
1465                         /*
1466                         The following filter loads external language files for TinyMCE plugins.
1467                         It takes an associative array 'plugin_name' => 'path', where path is the
1468                         include path to the file. The language file should follow the same format as
1469                         /tinymce/langs/wp-langs.php and should define a variable $strings that
1470                         holds all translated strings.
1471                         When this filter is not used, the function will try to load {mce_locale}.js.
1472                         If that is not found, en.js will be tried next.
1473                         */
1474                         $mce_external_languages = apply_filters('mce_external_languages', array());
1475
1476                         $loaded_langs = array();
1477                         $strings = '';
1478
1479                         if ( ! empty($mce_external_languages) ) {
1480                                 foreach ( $mce_external_languages as $name => $path ) {
1481                                         if ( @is_file($path) && @is_readable($path) ) {
1482                                                 include_once($path);
1483                                                 $ext_plugins .= $strings . "\n";
1484                                                 $loaded_langs[] = $name;
1485                                         }
1486                                 }
1487                         }
1488
1489                         foreach ( $mce_external_plugins as $name => $url ) {
1490
1491                                 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1492
1493                                 $plugins[] = '-' . $name;
1494
1495                                 $plugurl = dirname($url);
1496                                 $strings = $str1 = $str2 = '';
1497                                 if ( ! in_array($name, $loaded_langs) ) {
1498                                         $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1499                                         $path = WP_PLUGIN_DIR . $path . '/langs/';
1500
1501                                         if ( function_exists('realpath') )
1502                                                 $path = trailingslashit( realpath($path) );
1503
1504                                         if ( @is_file($path . $mce_locale . '.js') )
1505                                                 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1506
1507                                         if ( @is_file($path . $mce_locale . '_dlg.js') )
1508                                                 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1509
1510                                         if ( 'en' != $mce_locale && empty($strings) ) {
1511                                                 if ( @is_file($path . 'en.js') ) {
1512                                                         $str1 = @file_get_contents($path . 'en.js');
1513                                                         $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1514                                                 }
1515
1516                                                 if ( @is_file($path . 'en_dlg.js') ) {
1517                                                         $str2 = @file_get_contents($path . 'en_dlg.js');
1518                                                         $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1519                                                 }
1520                                         }
1521
1522                                         if ( ! empty($strings) )
1523                                                 $ext_plugins .= "\n" . $strings . "\n";
1524                                 }
1525
1526                                 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1527                                 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1528                         }
1529                 }
1530         }
1531
1532         if ( $teeny ) {
1533                 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1534                 $mce_buttons = implode($mce_buttons, ',');
1535                 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1536         } else {
1537                 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1538                 $mce_buttons = implode($mce_buttons, ',');
1539
1540                 $mce_buttons_2 = array( 'formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' );
1541                 $mce_buttons_2 = apply_filters('mce_buttons_2', $mce_buttons_2);
1542                 $mce_buttons_2 = implode($mce_buttons_2, ',');
1543
1544                 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1545                 $mce_buttons_3 = implode($mce_buttons_3, ',');
1546
1547                 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1548                 $mce_buttons_4 = implode($mce_buttons_4, ',');
1549         }
1550         $no_captions = (bool) apply_filters( 'disable_captions', '' );
1551
1552         // TinyMCE init settings
1553         $initArray = array (
1554                 'mode' => 'specific_textareas',
1555                 'editor_selector' => 'theEditor',
1556                 'width' => '100%',
1557                 'theme' => 'advanced',
1558                 'skin' => 'wp_theme',
1559                 'theme_advanced_buttons1' => $mce_buttons,
1560                 'theme_advanced_buttons2' => $mce_buttons_2,
1561                 'theme_advanced_buttons3' => $mce_buttons_3,
1562                 'theme_advanced_buttons4' => $mce_buttons_4,
1563                 'language' => $mce_locale,
1564                 'spellchecker_languages' => $mce_spellchecker_languages,
1565                 'theme_advanced_toolbar_location' => 'top',
1566                 'theme_advanced_toolbar_align' => 'left',
1567                 'theme_advanced_statusbar_location' => 'bottom',
1568                 'theme_advanced_resizing' => true,
1569                 'theme_advanced_resize_horizontal' => false,
1570                 'dialog_type' => 'modal',
1571                 'formats' => "{
1572                         alignleft : [
1573                                 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
1574                                 {selector : 'img,table', classes : 'alignleft'}
1575                         ],
1576                         aligncenter : [
1577                                 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
1578                                 {selector : 'img,table', classes : 'aligncenter'}
1579                         ],
1580                         alignright : [
1581                                 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
1582                                 {selector : 'img,table', classes : 'alignright'}
1583                         ],
1584                         strikethrough : {inline : 'del'}
1585                 }",
1586                 'relative_urls' => false,
1587                 'remove_script_host' => false,
1588                 'convert_urls' => false,
1589                 'apply_source_formatting' => false,
1590                 'remove_linebreaks' => true,
1591                 'gecko_spellcheck' => true,
1592                 'keep_styles' => false,
1593                 'entities' => '38,amp,60,lt,62,gt',
1594                 'accessibility_focus' => true,
1595                 'tabfocus_elements' => 'major-publishing-actions',
1596                 'media_strict' => false,
1597                 'paste_remove_styles' => true,
1598                 'paste_remove_spans' => true,
1599                 'paste_strip_class_attributes' => 'all',
1600                 'paste_text_use_dialog' => true,
1601                 'extended_valid_elements' => 'article[*],aside[*],audio[*],canvas[*],command[*],datalist[*],details[*],embed[*],figcaption[*],figure[*],footer[*],header[*],hgroup[*],keygen[*],mark[*],meter[*],nav[*],output[*],progress[*],section[*],source[*],summary,time[*],video[*],wbr',
1602                 'wpeditimage_disable_captions' => $no_captions,
1603                 'wp_fullscreen_content_css' => "$baseurl/plugins/wpfullscreen/css/wp-fullscreen.css",
1604                 'plugins' => implode( ',', $plugins ),
1605         );
1606
1607         if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
1608                 $mce_css = array();
1609                 $style_uri = get_stylesheet_directory_uri();
1610                 if ( ! is_child_theme() ) {
1611                         foreach ( $editor_styles as $file )
1612                                 $mce_css[] = "$style_uri/$file";
1613                 } else {
1614                         $style_dir    = get_stylesheet_directory();
1615                         $template_uri = get_template_directory_uri();
1616                         $template_dir = get_template_directory();
1617                         foreach ( $editor_styles as $file ) {
1618                                 if ( file_exists( "$template_dir/$file" ) )
1619                                         $mce_css[] = "$template_uri/$file";
1620                                 if ( file_exists( "$style_dir/$file" ) )
1621                                         $mce_css[] = "$style_uri/$file";
1622                         }
1623                 }
1624                 $mce_css = implode( ',', $mce_css );
1625         } else {
1626                 $mce_css = '';
1627         }
1628
1629         $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
1630
1631         if ( ! empty($mce_css) )
1632                 $initArray['content_css'] = $mce_css;
1633
1634         if ( is_array($settings) )
1635                 $initArray = array_merge($initArray, $settings);
1636
1637         // For people who really REALLY know what they're doing with TinyMCE
1638         // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1639         // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1640         // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1641         if ( $teeny ) {
1642                 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1643         } else {
1644                 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1645         }
1646
1647         if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1648                 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1649                 $initArray['theme_advanced_buttons4'] = '';
1650         }
1651
1652         if ( ! isset($concatenate_scripts) )
1653                 script_concat_settings();
1654
1655         $language = $initArray['language'];
1656
1657         $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1658                 && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
1659
1660         /**
1661          * Deprecated
1662          *
1663          * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1664          * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1665          * 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).
1666          */
1667         $version = apply_filters('tiny_mce_version', '');
1668         $version = 'ver=' . $tinymce_version . $version;
1669
1670         if ( 'en' != $language )
1671                 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1672
1673         $mce_options = '';
1674         foreach ( $initArray as $k => $v ) {
1675                 if ( is_bool($v) ) {
1676                         $val = $v ? 'true' : 'false';
1677                         $mce_options .= $k . ':' . $val . ', ';
1678                         continue;
1679                 } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
1680                         $mce_options .= $k . ':' . $v . ', ';
1681                         continue;
1682                 }
1683
1684                 $mce_options .= $k . ':"' . $v . '", ';
1685         }
1686
1687         $mce_options = rtrim( trim($mce_options), '\n\r,' );
1688
1689         do_action('before_wp_tiny_mce', $initArray); ?>
1690
1691 <script type="text/javascript">
1692 /* <![CDATA[ */
1693 tinyMCEPreInit = {
1694         base : "<?php echo $baseurl; ?>",
1695         suffix : "",
1696         query : "<?php echo $version; ?>",
1697         mceInit : {<?php echo $mce_options; ?>},
1698         load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1699 };
1700 /* ]]> */
1701 </script>
1702
1703 <?php
1704         if ( $compressed )
1705                 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=1&amp;$version'></script>\n";
1706         else
1707                 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1708
1709         if ( 'en' != $language && isset($lang) )
1710                 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1711         else
1712                 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1713 ?>
1714
1715 <script type="text/javascript">
1716 /* <![CDATA[ */
1717 <?php
1718         if ( $ext_plugins )
1719                 echo "$ext_plugins\n";
1720
1721         if ( ! $compressed ) {
1722 ?>
1723 (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');}});})();
1724 <?php } ?>
1725 tinyMCE.init(tinyMCEPreInit.mceInit);
1726 /* ]]> */
1727 </script>
1728 <?php
1729
1730 do_action('after_wp_tiny_mce', $initArray);
1731 }
1732
1733 // Load additional inline scripts based on active plugins.
1734 function wp_preload_dialogs($init) {
1735         $plugins = preg_split('/[ ,-]+/', $init['plugins']);
1736
1737         if ( in_array( 'wpdialogs', $plugins, true ) ) {
1738                 wp_print_scripts('wpdialogs-popup');
1739                 wp_print_styles('wp-jquery-ui-dialog');
1740         }
1741
1742         if ( in_array( 'wplink', $plugins, true ) ) {
1743                 require_once ABSPATH . 'wp-admin/includes/internal-linking.php';
1744                 ?><div style="display:none;"><?php wp_link_dialog(); ?></div><?php
1745                 wp_print_scripts('wplink');
1746                 wp_print_styles('wplink');
1747         }
1748
1749         // Distraction Free Writing mode
1750         if ( in_array( 'wpfullscreen', $plugins, true ) ) {
1751                 wp_fullscreen_html();
1752                 wp_print_scripts('wp-fullscreen');
1753         }
1754
1755         wp_print_scripts('word-count');
1756 }
1757
1758 function wp_quicktags() {
1759         global $tinymce_version;
1760
1761         wp_preload_dialogs( array( 'plugins' => 'wpdialogs,wplink,wpfullscreen' ) );
1762
1763         if ( !user_can_richedit() ) {
1764                 wp_enqueue_style( 'tinymce-buttons', includes_url('js/tinymce/themes/advanced/skins/wp_theme/ui.css'), array(), $tinymce_version );
1765                 wp_print_styles('tinymce-buttons');
1766         }
1767 }
1768
1769 function wp_print_editor_js() {
1770         wp_print_scripts('editor');
1771 }
1772
1773 function wp_fullscreen_html() {
1774         global $content_width, $post;
1775
1776         $width = isset($content_width) && 800 > $content_width ? $content_width : 800;
1777         $width = $width + 10; // compensate for the padding
1778         $dfw_width = get_user_setting( 'dfw_width', $width );
1779         $save = isset($post->post_status) && $post->post_status == 'publish' ? __('Update') : __('Save');
1780 ?>
1781 <div id="wp-fullscreen-body">
1782 <div id="fullscreen-topbar">
1783         <div id="wp-fullscreen-toolbar">
1784                 <div id="wp-fullscreen-close"><a href="#" onclick="fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
1785                 <div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
1786
1787                 <div id="wp-fullscreen-mode-bar"><div id="wp-fullscreen-modes">
1788                         <a href="#" onclick="fullscreen.switchmode('tinymce');return false;"><?php _e('Visual'); ?></a>
1789                         <a href="#" onclick="fullscreen.switchmode('html');return false;"><?php _e('HTML'); ?></a>
1790                 </div></div>
1791
1792                 <div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="wp_themeSkin">
1793 <?php
1794
1795         $media_link_type = 'image';
1796         if ( is_multisite() && ( ( ! $mu_media_buttons = get_site_option( 'mu_media_buttons' ) ) || empty( $mu_media_buttons['image'] ) ) )
1797                 $media_link_type = 'media';
1798
1799         $buttons = array(
1800                 // format: title, onclick, show in both editors
1801                 'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'onclick' => 'fullscreen.b();', 'both' => false ),
1802                 'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'onclick' => 'fullscreen.i();', 'both' => false ),
1803                 '0' => 'separator',
1804                 'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'onclick' => 'fullscreen.ul();', 'both' => false ),
1805                 'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'onclick' => 'fullscreen.ol();', 'both' => false ),
1806                 '1' => 'separator',
1807                 'blockquote' => array( 'title' => __('Blockquote (Alt+Shift+Q)'), 'onclick' => 'fullscreen.blockquote();', 'both' => false ),
1808                 'image' => array( 'title' => __('Insert/edit image (Alt + Shift + M)'), 'onclick' => "jQuery('#add_{$media_link_type}').click();", 'both' => true ),
1809                 '2' => 'separator',
1810                 'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'onclick' => 'fullscreen.link();', 'both' => true ),
1811                 'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'onclick' => 'fullscreen.unlink();', 'both' => false ),
1812                 '3' => 'separator',
1813                 'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'onclick' => 'fullscreen.help();', 'both' => false )
1814         );
1815
1816         $buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
1817
1818         foreach ( $buttons as $button => $args ) {
1819                 if ( 'separator' == $args ) { ?>
1820                         <div><span aria-orientation="vertical" role="separator" class="mceSeparator"></span></div>
1821 <?php           continue;
1822                 } ?>
1823
1824                 <div<?php if ( $args['both'] ) { ?> class="wp-fullscreen-both"<?php } ?>>
1825                 <a title="<?php echo $args['title']; ?>" onclick="<?php echo $args['onclick']; ?>return false;" class="mceButton mceButtonEnabled mce_<?php echo $button; ?>" href="#" id="wp_fs_<?php echo $button; ?>" role="button" aria-pressed="false">
1826                 <span class="mceIcon mce_<?php echo $button; ?>"></span>
1827                 </a>
1828                 </div>
1829 <?php
1830         } ?>
1831
1832                 </div></div>
1833
1834                 <div id="wp-fullscreen-save">
1835                         <span><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
1836                         <img src="images/wpspin_light.gif" alt="" />
1837                         <input type="button" class="button-primary" value="<?php echo $save; ?>" onclick="fullscreen.save();" />
1838                 </div>
1839
1840                 </div>
1841         </div>
1842 </div>
1843
1844 <div id="wp-fullscreen-wrap" style="width:<?php echo $dfw_width; ?>px;">
1845         <label id="wp-fullscreen-title-prompt-text" for="wp-fullscreen-title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
1846         <input type="text" id="wp-fullscreen-title" value="" autocomplete="off" />
1847
1848         <div id="wp-fullscreen-container">
1849                 <textarea id="wp_mce_fullscreen"></textarea>
1850         </div>
1851
1852         <div id="wp-fullscreen-status">
1853                 <div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
1854                 <div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
1855         </div>
1856 </div>
1857 </div>
1858
1859 <div class="fullscreen-overlay" id="fullscreen-overlay"></div>
1860 <div class="fullscreen-overlay fullscreen-fader fade-600" id="fullscreen-fader"></div>
1861 <?php
1862 }
1863
1864