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