Make WordPress Core

Ticket #18408: post.php

File post.php, 60.2 KB (added by ericlewis, 13 years ago)

wp-admin/includes/post.php

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