Wordpress 2.7.1
[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 post_data array 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         $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'];
33
34         if (!empty ( $post_data['post_author_override'] ) ) {
35                 $post_data['post_author'] = (int) $post_data['post_author_override'];
36         } else {
37                 if (!empty ( $post_data['post_author'] ) ) {
38                         $post_data['post_author'] = (int) $post_data['post_author'];
39                 } else {
40                         $post_data['post_author'] = (int) $post_data['user_ID'];
41                 }
42         }
43
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.' )
50                                 );
51                         }
52                 } else {
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.' )
57                                 );
58                         }
59                 }
60         }
61
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';
73
74         $previous_status = get_post_field('post_status',  isset($post_data['ID']) ? $post_data['ID'] : $post_data['temp_ID']);
75
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';
81         } else {
82                 $publish_cap = 'publish_posts';
83                 $edit_cap = 'edit_published_posts';
84         }
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';
88
89         if ( ! isset($post_data['post_status']) )
90                 $post_data['post_status'] = $previous_status;
91
92         if (!isset( $post_data['comment_status'] ))
93                 $post_data['comment_status'] = 'closed';
94
95         if (!isset( $post_data['ping_status'] ))
96                 $post_data['ping_status'] = 'closed';
97
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';
101                         break;
102                 }
103         }
104
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'] );
121         }
122
123         return $post_data;
124 }
125
126 /**
127  * Update an existing post with values provided in $_POST.
128  *
129  * @since unknown
130  *
131  * @param array $post_data Optional.
132  * @return int Post ID.
133  */
134 function edit_post( $post_data = null ) {
135
136         if ( empty($post_data) )
137                 $post_data = &$_POST;
138
139         $post_ID = (int) $post_data['post_ID'];
140
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.' ));
144         } else {
145                 if ( !current_user_can( 'edit_post', $post_ID ) )
146                         wp_die( __('You are not allowed to edit this post.' ));
147         }
148
149         // Autosave shouldn't save too soon after a real save
150         if ( 'autosave' == $post_data['action'] ) {
151                 $post =& get_post( $post_ID );
152                 $now = time();
153                 $then = strtotime($post->post_date_gmt . ' +0000');
154                 $delta = AUTOSAVE_INTERVAL / 2;
155                 if ( ($now - $then) < $delta )
156                         return $post_ID;
157         }
158
159         $post_data = _wp_translate_postdata( true, $post_data );
160         if ( is_wp_error($post_data) )
161                 wp_die( $post_data->get_error_message() );
162
163         if ( isset($post_data['visibility']) ) {
164                 switch ( $post_data['visibility'] ) {
165                         case 'public' :
166                                 $post_data['post_password'] = '';
167                                 break;
168                         case 'password' :
169                                 unset( $post_data['sticky'] );
170                                 break;
171                         case 'private' :
172                                 $post_data['post_status'] = 'private';
173                                 $post_data['post_password'] = '';
174                                 unset( $post_data['sticky'] );
175                                 break;
176                 }
177         }
178
179         // Meta Stuff
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'] );
183         }
184
185         if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
186                 foreach ( $post_data['deletemeta'] as $key => $value )
187                         delete_meta( $key );
188         }
189
190         add_meta( $post_ID );
191
192         wp_update_post( $post_data );
193
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 );
199
200         // Now that we have an ID we can fix any attachment anchor hrefs
201         _fix_attachment_links( $post_ID );
202
203         wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
204
205         if ( current_user_can( 'edit_others_posts' ) ) {
206                 if ( !empty($post_data['sticky']) )
207                         stick_post($post_ID);
208                 else
209                         unstick_post($post_ID);
210         }
211
212         return $post_ID;
213 }
214
215 /**
216  * {@internal Missing Short Description}}
217  *
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.
220  *
221  * @since unknown
222  *
223  * @return array
224  */
225 function bulk_edit_posts( $post_data = null ) {
226         global $wpdb;
227
228         if ( empty($post_data) )
229                 $post_data = &$_POST;
230
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.') );
234         } else {
235                 if ( ! current_user_can( 'edit_posts' ) )
236                         wp_die( __('You are not allowed to edit posts.') );
237         }
238
239         $post_IDs = array_map( 'intval', (array) $post_data['post'] );
240
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]);
245         }
246
247         if ( isset($post_data['post_category']) ) {
248                 if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
249                         $new_cats = array_map( absint, $post_data['post_category'] );
250                 else
251                         unset($post_data['post_category']);
252         }
253
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);
257         }
258
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'");
261                 $children = array();
262
263                 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
264                         $children[] = $parent;
265
266                         foreach ( $pages as $page ) {
267                                 if ( $page->ID == $parent ) {
268                                         $parent = $page->post_parent;
269                                         break;
270                                 }
271                         }
272                 }
273         }
274
275         $updated = $skipped = $locked = array();
276         foreach ( $post_IDs as $post_ID ) {
277
278                 if ( isset($children) && in_array($post_ID, $children) ) {
279                         $skipped[] = $post_ID;
280                         continue;
281                 }
282
283                 if ( wp_check_post_lock( $post_ID ) ) {
284                         $locked[] = $post_ID;
285                         continue;
286                 }
287
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) );
291                 }
292
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) );
296                 }
297
298                 $post_data['ID'] = $post_ID;
299                 $updated[] = wp_update_post( $post_data );
300
301                 if ( current_user_can( 'edit_others_posts' ) && isset( $post_data['sticky'] ) ) {
302                         if ( 'sticky' == $post_data['sticky'] )
303                                 stick_post( $post_ID );
304                         else
305                                 unstick_post( $post_ID );
306                 }
307
308         }
309
310         return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
311 }
312
313 /**
314  * Default post information to use when populating the "Write Post" form.
315  *
316  * @since unknown
317  *
318  * @return unknown
319  */
320 function get_default_post_to_edit() {
321         if ( !empty( $_REQUEST['post_title'] ) )
322                 $post_title = wp_specialchars( stripslashes( $_REQUEST['post_title'] ));
323         else if ( !empty( $_REQUEST['popuptitle'] ) ) {
324                 $post_title = wp_specialchars( stripslashes( $_REQUEST['popuptitle'] ));
325                 $post_title = funky_javascript_fix( $post_title );
326         } else {
327                 $post_title = '';
328         }
329
330         $post_content = '';
331         if ( !empty( $_REQUEST['content'] ) )
332                 $post_content = wp_specialchars( stripslashes( $_REQUEST['content'] ));
333         else if ( !empty( $post_title ) ) {
334                 $text       = wp_specialchars( stripslashes( urldecode( $_REQUEST['text'] ) ) );
335                 $text       = funky_javascript_fix( $text);
336                 $popupurl   = clean_url($_REQUEST['popupurl']);
337                 $post_content = '<a href="'.$popupurl.'">'.$post_title.'</a>'."\n$text";
338         }
339
340         if ( !empty( $_REQUEST['excerpt'] ) )
341                 $post_excerpt = wp_specialchars( stripslashes( $_REQUEST['excerpt'] ));
342         else
343                 $post_excerpt = '';
344
345         $post->ID = 0;
346         $post->post_name = '';
347         $post->post_author = '';
348         $post->post_date = '';
349         $post->post_password = '';
350         $post->post_status = 'draft';
351         $post->post_type = 'post';
352         $post->to_ping = '';
353         $post->pinged = '';
354         $post->comment_status = get_option( 'default_comment_status' );
355         $post->ping_status = get_option( 'default_ping_status' );
356         $post->post_pingback = get_option( 'default_pingback_flag' );
357         $post->post_category = get_option( 'default_category' );
358         $post->post_content = apply_filters( 'default_content', $post_content);
359         $post->post_title = apply_filters( 'default_title', $post_title );
360         $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt);
361         $post->page_template = 'default';
362         $post->post_parent = 0;
363         $post->menu_order = 0;
364
365         return $post;
366 }
367
368 /**
369  * {@internal Missing Short Description}}
370  *
371  * @since unknown
372  *
373  * @return unknown
374  */
375 function get_default_page_to_edit() {
376         $page = get_default_post_to_edit();
377         $page->post_type = 'page';
378         return $page;
379 }
380
381 /**
382  * Get an existing post and format it for editing.
383  *
384  * @since unknown
385  *
386  * @param unknown_type $id
387  * @return unknown
388  */
389 function get_post_to_edit( $id ) {
390
391         $post = get_post( $id, OBJECT, 'edit' );
392
393         if ( $post->post_type == 'page' )
394                 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
395
396         return $post;
397 }
398
399 /**
400  * {@internal Missing Short Description}}
401  *
402  * @since unknown
403  *
404  * @param unknown_type $title
405  * @param unknown_type $content
406  * @param unknown_type $post_date
407  * @return unknown
408  */
409 function post_exists($title, $content = '', $post_date = '') {
410         global $wpdb;
411
412         $title = stripslashes($title);
413         $content = stripslashes($content);
414         $post_date = stripslashes($post_date);
415
416         if (!empty ($post_date))
417                 $post_date = $wpdb->prepare("AND post_date = %s", $post_date);
418
419         if (!empty ($title))
420                 return $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title = %s $post_date", $title) );
421         else
422                 if (!empty ($content))
423                         return $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_content = %s $post_date", $content) );
424
425         return 0;
426 }
427
428 /**
429  * Creates a new post from the "Write Post" form using $_POST information.
430  *
431  * @since unknown
432  *
433  * @return unknown
434  */
435 function wp_write_post() {
436         global $user_ID;
437
438         if ( 'page' == $_POST['post_type'] ) {
439                 if ( !current_user_can( 'edit_pages' ) )
440                         return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this blog.' ) );
441         } else {
442                 if ( !current_user_can( 'edit_posts' ) )
443                         return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this blog.' ) );
444         }
445
446
447         // Check for autosave collisions
448         $temp_id = false;
449         if ( isset($_POST['temp_ID']) ) {
450                 $temp_id = (int) $_POST['temp_ID'];
451                 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
452                         $draft_ids = array();
453                 foreach ( $draft_ids as $temp => $real )
454                         if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
455                                 unset($draft_ids[$temp]);
456
457                 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
458                         $_POST['post_ID'] = $draft_ids[$temp_id];
459                         unset($_POST['temp_ID']);
460                         update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
461                         return edit_post();
462                 }
463         }
464
465         $translated = _wp_translate_postdata( false );
466         if ( is_wp_error($translated) )
467                 return $translated;
468
469         if ( isset($_POST['visibility']) ) {
470                 switch ( $_POST['visibility'] ) {
471                         case 'public' :
472                                 $_POST['post_password'] = '';
473                                 break;
474                         case 'password' :
475                                 unset( $_POST['sticky'] );
476                                 break;
477                         case 'private' :
478                                 $_POST['post_status'] = 'private';
479                                 $_POST['post_password'] = '';
480                                 unset( $_POST['sticky'] );
481                                 break;
482                 }
483         }
484
485         // Create the post.
486         $post_ID = wp_insert_post( $_POST );
487         if ( is_wp_error( $post_ID ) )
488                 return $post_ID;
489
490         if ( empty($post_ID) )
491                 return 0;
492
493         add_meta( $post_ID );
494
495         // Reunite any orphaned attachments with their parent
496         if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
497                 $draft_ids = array();
498         if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
499                 _relocate_children( $draft_temp_id, $post_ID );
500         if ( $temp_id && $temp_id != $draft_temp_id )
501                 _relocate_children( $temp_id, $post_ID );
502
503         // Update autosave collision detection
504         if ( $temp_id ) {
505                 $draft_ids[$temp_id] = $post_ID;
506                 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
507         }
508
509         // Now that we have an ID we can fix any attachment anchor hrefs
510         _fix_attachment_links( $post_ID );
511
512         wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
513
514         return $post_ID;
515 }
516
517 /**
518  * Calls wp_write_post() and handles the errors.
519  *
520  * @since unknown
521  *
522  * @return unknown
523  */
524 function write_post() {
525         $result = wp_write_post();
526         if( is_wp_error( $result ) )
527                 wp_die( $result->get_error_message() );
528         else
529                 return $result;
530 }
531
532 //
533 // Post Meta
534 //
535
536 /**
537  * {@internal Missing Short Description}}
538  *
539  * @since unknown
540  *
541  * @param unknown_type $post_ID
542  * @return unknown
543  */
544 function add_meta( $post_ID ) {
545         global $wpdb;
546         $post_ID = (int) $post_ID;
547
548         $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
549
550         $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
551         $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
552         $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes( trim( $_POST['metavalue'] ) ) ) : '';
553
554         if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
555                 // We have a key/value pair. If both the select and the
556                 // input for the key have data, the input takes precedence:
557
558                 if ('#NONE#' != $metakeyselect)
559                         $metakey = $metakeyselect;
560
561                 if ( $metakeyinput)
562                         $metakey = $metakeyinput; // default
563
564                 if ( in_array($metakey, $protected) )
565                         return false;
566
567                 wp_cache_delete($post_ID, 'post_meta');
568
569                 $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value ) VALUES (%s, %s, %s)", $post_ID, $metakey, $metavalue) );
570                 return $wpdb->insert_id;
571         }
572         return false;
573 } // add_meta
574
575 /**
576  * {@internal Missing Short Description}}
577  *
578  * @since unknown
579  *
580  * @param unknown_type $mid
581  * @return unknown
582  */
583 function delete_meta( $mid ) {
584         global $wpdb;
585         $mid = (int) $mid;
586
587         $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
588         wp_cache_delete($post_id, 'post_meta');
589
590         return $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
591 }
592
593 /**
594  * Get a list of previously defined keys.
595  *
596  * @since unknown
597  *
598  * @return unknown
599  */
600 function get_meta_keys() {
601         global $wpdb;
602
603         $keys = $wpdb->get_col( "
604                         SELECT meta_key
605                         FROM $wpdb->postmeta
606                         GROUP BY meta_key
607                         ORDER BY meta_key" );
608
609         return $keys;
610 }
611
612 /**
613  * {@internal Missing Short Description}}
614  *
615  * @since unknown
616  *
617  * @param unknown_type $mid
618  * @return unknown
619  */
620 function get_post_meta_by_id( $mid ) {
621         global $wpdb;
622         $mid = (int) $mid;
623
624         $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
625         if ( is_serialized_string( $meta->meta_value ) )
626                 $meta->meta_value = maybe_unserialize( $meta->meta_value );
627         return $meta;
628 }
629
630 /**
631  * {@internal Missing Short Description}}
632  *
633  * Some postmeta stuff.
634  *
635  * @since unknown
636  *
637  * @param unknown_type $postid
638  * @return unknown
639  */
640 function has_meta( $postid ) {
641         global $wpdb;
642
643         return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
644                         FROM $wpdb->postmeta WHERE post_id = %d
645                         ORDER BY meta_key,meta_id", $postid), ARRAY_A );
646
647 }
648
649 /**
650  * {@internal Missing Short Description}}
651  *
652  * @since unknown
653  *
654  * @param unknown_type $meta_id
655  * @param unknown_type $meta_key
656  * @param unknown_type $meta_value
657  * @return unknown
658  */
659 function update_meta( $meta_id, $meta_key, $meta_value ) {
660         global $wpdb;
661
662         $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
663
664         if ( in_array($meta_key, $protected) )
665                 return false;
666
667         $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
668         wp_cache_delete($post_id, 'post_meta');
669
670         $meta_value = maybe_serialize( stripslashes( $meta_value ));
671         $meta_id = (int) $meta_id;
672
673         $data  = compact( 'meta_key', 'meta_value' );
674         $where = compact( 'meta_id' );
675
676         return $wpdb->update( $wpdb->postmeta, $data, $where );
677 }
678
679 //
680 // Private
681 //
682
683 /**
684  * Replace hrefs of attachment anchors with up-to-date permalinks.
685  *
686  * @since unknown
687  * @access private
688  *
689  * @param unknown_type $post_ID
690  * @return unknown
691  */
692 function _fix_attachment_links( $post_ID ) {
693
694         $post = & get_post( $post_ID, ARRAY_A );
695
696         $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
697
698         // See if we have any rel="attachment" links
699         if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
700                 return;
701
702         $i = 0;
703         $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
704         foreach ( $anchor_matches[0] as $anchor ) {
705                 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
706                         continue;
707
708                 $id = (int) $id_matches[3];
709
710                 // While we have the attachment ID, let's adopt any orphans.
711                 $attachment = & get_post( $id, ARRAY_A );
712                 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
713                         $attachment['post_parent'] = $post_ID;
714                         // Escape data pulled from DB.
715                         $attachment = add_magic_quotes( $attachment);
716                         wp_update_post( $attachment);
717                 }
718
719                 $post_search[$i] = $anchor;
720                 $post_replace[$i] = preg_replace( "#href=(\"|')[^'\"]*\\1#e", "stripslashes( 'href=\\1' ).get_attachment_link( $id ).stripslashes( '\\1' )", $anchor );
721                 ++$i;
722         }
723
724         $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
725
726         // Escape data pulled from DB.
727         $post = add_magic_quotes( $post);
728
729         return wp_update_post( $post);
730 }
731
732 /**
733  * Move child posts to a new parent.
734  *
735  * @since unknown
736  * @access private
737  *
738  * @param unknown_type $old_ID
739  * @param unknown_type $new_ID
740  * @return unknown
741  */
742 function _relocate_children( $old_ID, $new_ID ) {
743         global $wpdb;
744         $old_ID = (int) $old_ID;
745         $new_ID = (int) $new_ID;
746         return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_parent = %d WHERE post_parent = %d", $new_ID, $old_ID) );
747 }
748
749 /**
750  * {@internal Missing Short Description}}
751  *
752  * @since unknown
753  *
754  * @param unknown_type $type
755  * @return unknown
756  */
757 function get_available_post_statuses($type = 'post') {
758         $stati = wp_count_posts($type);
759
760         return array_keys(get_object_vars($stati));
761 }
762
763 /**
764  * {@internal Missing Short Description}}
765  *
766  * @since unknown
767  *
768  * @param unknown_type $q
769  * @return unknown
770  */
771 function wp_edit_posts_query( $q = false ) {
772         if ( false === $q )
773                 $q = $_GET;
774         $q['m']   = isset($q['m']) ? (int) $q['m'] : 0;
775         $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
776         $post_stati  = array(   //      array( adj, noun )
777                                 'publish' => array(__('Published'), __('Published posts'), __ngettext_noop('Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>')),
778                                 'future' => array(__('Scheduled'), __('Scheduled posts'), __ngettext_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>')),
779                                 'pending' => array(__('Pending Review'), __('Pending posts'), __ngettext_noop('Pending Review <span class="count">(%s)</span>', 'Pending Review <span class="count">(%s)</span>')),
780                                 'draft' => array(__('Draft'), _c('Drafts|manage posts header'), __ngettext_noop('Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>')),
781                                 'private' => array(__('Private'), __('Private posts'), __ngettext_noop('Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>')),
782                         );
783
784         $post_stati = apply_filters('post_stati', $post_stati);
785
786         $avail_post_stati = get_available_post_statuses('post');
787
788         $post_status_q = '';
789         if ( isset($q['post_status']) && in_array( $q['post_status'], array_keys($post_stati) ) ) {
790                 $post_status_q = '&post_status=' . $q['post_status'];
791                 $post_status_q .= '&perm=readable';
792         }
793
794         if ( isset($q['post_status']) && 'pending' === $q['post_status'] ) {
795                 $order = 'ASC';
796                 $orderby = 'modified';
797         } elseif ( isset($q['post_status']) && 'draft' === $q['post_status'] ) {
798                 $order = 'DESC';
799                 $orderby = 'modified';
800         } else {
801                 $order = 'DESC';
802                 $orderby = 'date';
803         }
804
805         wp("post_type=post&what_to_show=posts$post_status_q&posts_per_page=15&order=$order&orderby=$orderby");
806
807         return array($post_stati, $avail_post_stati);
808 }
809
810 /**
811  * {@internal Missing Short Description}}
812  *
813  * @since unknown
814  *
815  * @param unknown_type $type
816  * @return unknown
817  */
818 function get_available_post_mime_types($type = 'attachment') {
819         global $wpdb;
820
821         $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
822         return $types;
823 }
824
825 /**
826  * {@internal Missing Short Description}}
827  *
828  * @since unknown
829  *
830  * @param unknown_type $q
831  * @return unknown
832  */
833 function wp_edit_attachments_query( $q = false ) {
834         if ( false === $q )
835                 $q = $_GET;
836
837         $q['m']   = isset( $q['m'] ) ? (int) $q['m'] : 0;
838         $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
839         $q['post_type'] = 'attachment';
840         $q['post_status'] = 'any';
841         $q['posts_per_page'] = 15;
842         $post_mime_types = array(       //      array( adj, noun )
843                                 'image' => array(__('Images'), __('Manage Images'), __ngettext_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
844                                 'audio' => array(__('Audio'), __('Manage Audio'), __ngettext_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
845                                 'video' => array(__('Video'), __('Manage Video'), __ngettext_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
846                         );
847         $post_mime_types = apply_filters('post_mime_types', $post_mime_types);
848
849         $avail_post_mime_types = get_available_post_mime_types('attachment');
850
851         if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
852                 unset($q['post_mime_type']);
853
854         wp($q);
855
856         return array($post_mime_types, $avail_post_mime_types);
857 }
858
859 /**
860  * {@internal Missing Short Description}}
861  *
862  * @since unknown
863  *
864  * @param unknown_type $id
865  * @param unknown_type $page
866  * @return unknown
867  */
868 function postbox_classes( $id, $page ) {
869         if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id )
870                 return '';
871         $current_user = wp_get_current_user();
872         if ( $closed = get_user_option('closedpostboxes_'.$page, 0, false ) ) {
873                 if ( !is_array( $closed ) ) return '';
874                 return in_array( $id, $closed )? 'if-js-closed' : '';
875         } else {
876                 return '';
877         }
878 }
879
880 /**
881  * {@internal Missing Short Description}}
882  *
883  * @since unknown
884  *
885  * @param unknown_type $id
886  * @param unknown_type $title
887  * @param unknown_type $name
888  * @return unknown
889  */
890 function get_sample_permalink($id, $title=null, $name = null) {
891         $post = &get_post($id);
892         if (!$post->ID) {
893                 return array('', '');
894         }
895         $original_status = $post->post_status;
896         $original_date = $post->post_date;
897         $original_name = $post->post_name;
898
899         // Hack: get_permalink would return ugly permalink for
900         // drafts, so we will fake, that our post is published
901         if (in_array($post->post_status, array('draft', 'pending'))) {
902                 $post->post_status = 'publish';
903                 $post->post_name = sanitize_title($post->post_name? $post->post_name : $post->post_title, $post->ID);
904         }
905
906         // If the user wants to set a new name -- override the current one
907         // Note: if empty name is supplied -- use the title instead, see #6072
908         if (!is_null($name)) {
909                 $post->post_name = sanitize_title($name? $name : $title, $post->ID);
910         }
911
912         $post->filter = 'sample'; 
913
914         $permalink = get_permalink($post, true);
915
916         // Handle page hierarchy
917         if ( 'page' == $post->post_type ) {
918                 $uri = get_page_uri($post->ID);
919                 $uri = untrailingslashit($uri);
920                 $uri = strrev( stristr( strrev( $uri ), '/' ) );
921                 $uri = untrailingslashit($uri);
922                 if ( !empty($uri) )
923                         $uri .='/';
924                 $permalink = str_replace('%pagename%', "${uri}%pagename%", $permalink);
925         }
926
927         $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
928         $post->post_status = $original_status;
929         $post->post_date = $original_date;
930         $post->post_name = $original_name;
931         unset($post->filter);
932
933         return $permalink;
934 }
935
936 /**
937  * {@internal Missing Short Description}}
938  *
939  * @since unknown
940  *
941  * @param unknown_type $id
942  * @param unknown_type $new_title
943  * @param unknown_type $new_slug
944  * @return unknown
945  */
946 function get_sample_permalink_html($id, $new_title=null, $new_slug=null) {
947         $post = &get_post($id);
948         list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
949         if (false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%')) {
950                 return '';
951         }
952         $title = __('Click to edit this part of the permalink');
953         if (function_exists('mb_strlen')) {
954                 if (mb_strlen($post_name) > 30) {
955                         $post_name_abridged = mb_substr($post_name, 0, 14). '&hellip;' . mb_substr($post_name, -14);
956                 } else {
957                         $post_name_abridged = $post_name;
958                 }
959         } else {
960                 if (strlen($post_name) > 30) {
961                         $post_name_abridged = substr($post_name, 0, 14). '&hellip;' . substr($post_name, -14);
962                 } else {
963                         $post_name_abridged = $post_name;
964                 }
965         }
966         $post_name_html = '<span id="editable-post-name" title="'.$title.'">'.$post_name_abridged.'</span><span id="editable-post-name-full">'.$post_name.'</span>';
967         $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
968         $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $display_link . "</span>\n";
969         $return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button" onclick="edit_permalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
970         return $return;
971 }
972
973 /**
974  * {@internal Missing Short Description}}
975  *
976  * @since unknown
977  *
978  * @param unknown_type $post_id
979  * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
980  */
981 function wp_check_post_lock( $post_id ) {
982         global $current_user;
983
984         if ( !$post = get_post( $post_id ) )
985                 return false;
986
987         $lock = get_post_meta( $post->ID, '_edit_lock', true );
988         $last = get_post_meta( $post->ID, '_edit_last', true );
989
990         $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
991
992         if ( $lock && $lock > time() - $time_window && $last != $current_user->ID )
993                 return $last;
994         return false;
995 }
996
997 /**
998  * {@internal Missing Short Description}}
999  *
1000  * @since unknown
1001  *
1002  * @param unknown_type $post_id
1003  * @return unknown
1004  */
1005 function wp_set_post_lock( $post_id ) {
1006         global $current_user;
1007         if ( !$post = get_post( $post_id ) )
1008                 return false;
1009         if ( !$current_user || !$current_user->ID )
1010                 return false;
1011
1012         $now = time();
1013
1014         if ( !add_post_meta( $post->ID, '_edit_lock', $now, true ) )
1015                 update_post_meta( $post->ID, '_edit_lock', $now );
1016         if ( !add_post_meta( $post->ID, '_edit_last', $current_user->ID, true ) )
1017                 update_post_meta( $post->ID, '_edit_last', $current_user->ID );
1018 }
1019
1020 /**
1021  * Creates autosave data for the specified post from $_POST data.
1022  *
1023  * @package WordPress
1024  * @subpackage Post_Revisions
1025  * @since 2.6.0
1026  *
1027  * @uses _wp_translate_postdata()
1028  * @uses _wp_post_revision_fields()
1029  */
1030 function wp_create_post_autosave( $post_id ) {
1031         $translated = _wp_translate_postdata( true );
1032         if ( is_wp_error( $translated ) )
1033                 return $translated;
1034
1035         // Only store one autosave.  If there is already an autosave, overwrite it.
1036         if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1037                 $new_autosave = _wp_post_revision_fields( $_POST, true );
1038                 $new_autosave['ID'] = $old_autosave->ID;
1039                 return wp_update_post( $new_autosave );
1040         }
1041
1042         // Otherwise create the new autosave as a special post revision
1043         return _wp_put_post_revision( $_POST, true );
1044 }
1045
1046 /**
1047  * Save draft or manually autosave for showing preview.
1048  *
1049  * @package WordPress
1050  * @since 2.7
1051  *
1052  * @uses wp_write_post()
1053  * @uses edit_post()
1054  * @uses get_post()
1055  * @uses current_user_can()
1056  * @uses wp_create_post_autosave()
1057  *
1058  * @return str URL to redirect to show the preview
1059  */
1060 function post_preview() {
1061
1062         $post_ID = (int) $_POST['post_ID'];
1063         if ( $post_ID < 1 )
1064                 wp_die( __('Preview not available. Please save as a draft first.') );
1065
1066         if ( isset($_POST['catslist']) )
1067                 $_POST['post_category'] = explode(",", $_POST['catslist']);
1068
1069         if ( isset($_POST['tags_input']) )
1070                 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1071
1072         if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1073                 unset($_POST['post_category']);
1074
1075         $_POST['ID'] = $post_ID;
1076         $post = get_post($post_ID);
1077
1078         if ( 'page' == $post->post_type ) {
1079                 if ( !current_user_can('edit_page', $post_ID) )
1080                         wp_die(__('You are not allowed to edit this page.'));
1081         } else {
1082                 if ( !current_user_can('edit_post', $post_ID) )
1083                         wp_die(__('You are not allowed to edit this post.'));
1084         }
1085
1086         if ( 'draft' == $post->post_status ) {
1087                 $id = edit_post();
1088         } else { // Non drafts are not overwritten.  The autosave is stored in a special post revision.
1089                 $id = wp_create_post_autosave( $post->ID );
1090                 if ( ! is_wp_error($id) )
1091                         $id = $post->ID;
1092         }
1093
1094         if ( is_wp_error($id) )
1095                 wp_die( $id->get_error_message() );
1096
1097         if ( $_POST['post_status'] == 'draft'  ) {
1098                 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1099         } else {
1100                 $nonce = wp_create_nonce('post_preview_' . $id);
1101                 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1102         }
1103
1104         return $url;
1105 }
1106
1107 /**
1108  * Adds the TinyMCE editor used on the Write and Edit screens.
1109  *
1110  * Has option to output a trimmed down version used in Press This.
1111  *
1112  * @package WordPress
1113  * @since 2.7
1114  */
1115 function wp_tiny_mce( $teeny = false ) {
1116         if ( ! user_can_richedit() )
1117                 return;
1118
1119         $baseurl = includes_url('js/tinymce');
1120
1121         $mce_css = $baseurl . '/wordpress.css';
1122         $mce_css = apply_filters('mce_css', $mce_css);
1123
1124         $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1125
1126         /*
1127         The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1128         By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1129         The + sign marks the default language. More information:
1130         http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1131         */
1132         $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');
1133
1134         if ( $teeny ) {
1135                 $plugins = apply_filters( 'teeny_mce_plugins', array('safari', 'inlinepopups', 'media', 'autosave', 'fullscreen') );
1136                 $ext_plugins = '';
1137         } else {
1138                 $plugins = array( 'safari', 'inlinepopups', 'autosave', 'spellchecker', 'paste', 'wordpress', 'media', 'fullscreen', 'wpeditimage', 'wpgallery' );
1139
1140                 /*
1141                 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1142                 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1143                 The url should be absolute and should include the js file name to be loaded. Example:
1144                 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1145                 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1146                 */
1147                 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1148
1149                 $ext_plugins = "\n";
1150                 if ( ! empty($mce_external_plugins) ) {
1151
1152                         /*
1153                         The following filter loads external language files for TinyMCE plugins.
1154                         It takes an associative array 'plugin_name' => 'path', where path is the
1155                         include path to the file. The language file should follow the same format as
1156                         /tinymce/langs/wp-langs.php and should define a variable $strings that
1157                         holds all translated strings.
1158                         When this filter is not used, the function will try to load {mce_locale}.js.
1159                         If that is not found, en.js will be tried next.
1160                         */
1161                         $mce_external_languages = apply_filters('mce_external_languages', array());
1162
1163                         $loaded_langs = array();
1164                         $strings = '';
1165
1166                         if ( ! empty($mce_external_languages) ) {
1167                                 foreach ( $mce_external_languages as $name => $path ) {
1168                                         if ( @is_file($path) && @is_readable($path) ) {
1169                                                 include_once($path);
1170                                                 $ext_plugins .= $strings . "\n";
1171                                                 $loaded_langs[] = $name;
1172                                         }
1173                                 }
1174                         }
1175
1176                         foreach ( $mce_external_plugins as $name => $url ) {
1177
1178                                 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1179
1180                                 $plugins[] = '-' . $name;
1181
1182                                 $plugurl = dirname($url);
1183                                 $strings = $str1 = $str2 = '';
1184                                 if ( ! in_array($name, $loaded_langs) ) {
1185                                         $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1186                                         $path = WP_PLUGIN_DIR . $path . '/langs/';
1187
1188                                         if ( function_exists('realpath') )
1189                                                 $path = trailingslashit( realpath($path) );
1190
1191                                         if ( @is_file($path . $mce_locale . '.js') )
1192                                                 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1193
1194                                         if ( @is_file($path . $mce_locale . '_dlg.js') )
1195                                                 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1196
1197                                         if ( 'en' != $mce_locale && empty($strings) ) {
1198                                                 if ( @is_file($path . 'en.js') ) {
1199                                                         $str1 = @file_get_contents($path . 'en.js');
1200                                                         $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1201                                                 }
1202
1203                                                 if ( @is_file($path . 'en_dlg.js') ) {
1204                                                         $str2 = @file_get_contents($path . 'en_dlg.js');
1205                                                         $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1206                                                 }
1207                                         }
1208
1209                                         if ( ! empty($strings) )
1210                                                 $ext_plugins .= "\n" . $strings . "\n";
1211                                 }
1212
1213                                 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1214                                 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1215                         }
1216                 }
1217         }
1218
1219         $plugins = implode($plugins, ',');
1220
1221         if ( $teeny ) {
1222                 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1223                 $mce_buttons = implode($mce_buttons, ',');
1224                 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1225         } else {
1226                 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1227                 $mce_buttons = implode($mce_buttons, ',');
1228
1229                 $mce_buttons_2 = apply_filters('mce_buttons_2', array('formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'media', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' ));
1230                 $mce_buttons_2 = implode($mce_buttons_2, ',');
1231
1232                 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1233                 $mce_buttons_3 = implode($mce_buttons_3, ',');
1234
1235                 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1236                 $mce_buttons_4 = implode($mce_buttons_4, ',');
1237         }
1238         $no_captions = ( apply_filters( 'disable_captions', '' ) ) ? true : false;
1239
1240         // TinyMCE init settings
1241         $initArray = array (
1242                 'mode' => 'none',
1243                 'onpageload' => 'switchEditors.edInit',
1244                 'width' => '100%',
1245                 'theme' => 'advanced',
1246                 'skin' => 'wp_theme',
1247                 'theme_advanced_buttons1' => "$mce_buttons",
1248                 'theme_advanced_buttons2' => "$mce_buttons_2",
1249                 'theme_advanced_buttons3' => "$mce_buttons_3",
1250                 'theme_advanced_buttons4' => "$mce_buttons_4",
1251                 'language' => "$mce_locale",
1252                 'spellchecker_languages' => "$mce_spellchecker_languages",
1253                 'theme_advanced_toolbar_location' => 'top',
1254                 'theme_advanced_toolbar_align' => 'left',
1255                 'theme_advanced_statusbar_location' => 'bottom',
1256                 'theme_advanced_resizing' => true,
1257                 'theme_advanced_resize_horizontal' => false,
1258                 'dialog_type' => 'modal',
1259                 'relative_urls' => false,
1260                 'remove_script_host' => false,
1261                 'convert_urls' => false,
1262                 'apply_source_formatting' => false,
1263                 'remove_linebreaks' => true,
1264                 'paste_convert_middot_lists' => true,
1265                 'paste_remove_spans' => true,
1266                 'paste_remove_styles' => true,
1267                 'gecko_spellcheck' => true,
1268                 'entities' => '38,amp,60,lt,62,gt',
1269                 'accessibility_focus' => true,
1270                 'tab_focus' => ':prev,:next',
1271                 'content_css' => "$mce_css",
1272                 'save_callback' => 'switchEditors.saveCallback',
1273                 'wpeditimage_disable_captions' => $no_captions,
1274                 'plugins' => "$plugins"
1275         );
1276
1277         // For people who really REALLY know what they're doing with TinyMCE
1278         // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1279         // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1280         // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1281         if ( $teeny ) {
1282                 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1283         } else {
1284                 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1285         }
1286
1287         $language = $initArray['language'];
1288
1289         $ver = apply_filters('tiny_mce_version', '3101');
1290
1291         if ( 'en' != $language )
1292                 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1293
1294         $mce_options = '';
1295         foreach ( $initArray as $k => $v )
1296             $mce_options .= $k . ':"' . $v . '", ';
1297
1298         $mce_options = rtrim( trim($mce_options), '\n\r,' ); ?>
1299
1300 <script type="text/javascript">
1301 /* <![CDATA[ */
1302 tinyMCEPreInit = {
1303         base : "<?php echo $baseurl; ?>",
1304         suffix : "",
1305         query : "ver=<?php echo $ver; ?>",
1306         mceInit : {<?php echo $mce_options; ?>},
1307
1308         go : function() {
1309                 var t = this, sl = tinymce.ScriptLoader, ln = t.mceInit.language, th = t.mceInit.theme, pl = t.mceInit.plugins;
1310
1311                 sl.markDone(t.base + '/langs/' + ln + '.js');
1312
1313                 sl.markDone(t.base + '/themes/' + th + '/langs/' + ln + '.js');
1314                 sl.markDone(t.base + '/themes/' + th + '/langs/' + ln + '_dlg.js');
1315
1316                 tinymce.each(pl.split(','), function(n) {
1317                         if (n && n.charAt(0) != '-') {
1318                                 sl.markDone(t.base + '/plugins/' + n + '/langs/' + ln + '.js');
1319                                 sl.markDone(t.base + '/plugins/' + n + '/langs/' + ln + '_dlg.js');
1320                         }
1321                 });
1322         },
1323
1324         load_ext : function(url,lang) {
1325                 var sl = tinymce.ScriptLoader;
1326
1327                 sl.markDone(url + '/langs/' + lang + '.js');
1328                 sl.markDone(url + '/langs/' + lang + '_dlg.js');
1329         }
1330 };
1331 /* ]]> */
1332 </script>
1333 <script type="text/javascript" src="<?php echo $baseurl; ?>/tiny_mce.js?ver=<?php echo $ver; ?>"></script>
1334 <?php if ( 'en' != $language && isset($lang) ) { ?>
1335 <script type="text/javascript">
1336 <?php echo $lang; ?>
1337 </script>
1338 <?php } else { ?>
1339 <script type="text/javascript" src="<?php echo $baseurl; ?>/langs/wp-langs-en.js?ver=<?php echo $ver; ?>"></script>
1340 <?php } ?>
1341 <script type="text/javascript">
1342 <?php if ( $ext_plugins ) echo $ext_plugins; ?>
1343
1344 // Mark translations as done
1345 tinyMCEPreInit.go();
1346
1347 // Init
1348 tinyMCE.init(tinyMCEPreInit.mceInit);
1349 </script>
1350
1351 <?php
1352 }
1353 ?>