3 * WordPress Post Administration API.
6 * @subpackage Administration
10 * Rename $_POST data from form names to DB post columns.
12 * Manipulates $_POST directly.
17 * @param bool $update Are we updating a pre-existing post?
18 * @param array $post_data Array of post data. Defaults to the contents of $_POST.
19 * @return object|bool WP_Error on failure, true on success.
21 function _wp_translate_postdata( $update = false, $post_data = null ) {
23 if ( empty($post_data) )
27 $post_data['ID'] = (int) $post_data['post_ID'];
28 $post_data['post_content'] = isset($post_data['content']) ? $post_data['content'] : '';
29 $post_data['post_excerpt'] = isset($post_data['excerpt']) ? $post_data['excerpt'] : '';
30 $post_data['post_parent'] = isset($post_data['parent_id'])? $post_data['parent_id'] : '';
31 if ( isset($post_data['trackback_url']) )
32 $post_data['to_ping'] = $post_data['trackback_url'];
34 if ( !isset($post_data['user_ID']) )
35 $post_data['user_ID'] = $GLOBALS['user_ID'];
37 if (!empty ( $post_data['post_author_override'] ) ) {
38 $post_data['post_author'] = (int) $post_data['post_author_override'];
40 if (!empty ( $post_data['post_author'] ) ) {
41 $post_data['post_author'] = (int) $post_data['post_author'];
43 $post_data['post_author'] = (int) $post_data['user_ID'];
47 $ptype = get_post_type_object( $post_data['post_type'] );
48 if ( isset($post_data['user_ID']) && ($post_data['post_author'] != $post_data['user_ID']) ) {
49 if ( !current_user_can( $ptype->cap->edit_others_posts ) ) {
50 if ( 'page' == $post_data['post_type'] ) {
51 return new WP_Error( 'edit_others_pages', $update ?
52 __( 'You are not allowed to edit pages as this user.' ) :
53 __( 'You are not allowed to create pages as this user.' )
56 return new WP_Error( 'edit_others_posts', $update ?
57 __( 'You are not allowed to edit posts as this user.' ) :
58 __( 'You are not allowed to post as this user.' )
64 // What to do based on which button they pressed
65 if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
66 $post_data['post_status'] = 'draft';
67 if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
68 $post_data['post_status'] = 'private';
69 if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
70 $post_data['post_status'] = 'publish';
71 if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
72 $post_data['post_status'] = 'draft';
73 if ( isset($post_data['pending']) && '' != $post_data['pending'] )
74 $post_data['post_status'] = 'pending';
76 if ( isset( $post_data['ID'] ) )
77 $post_id = $post_data['ID'];
80 $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
82 // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
83 // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
84 if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
85 if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
86 $post_data['post_status'] = 'pending';
88 if ( ! isset($post_data['post_status']) )
89 $post_data['post_status'] = $previous_status;
91 if (!isset( $post_data['comment_status'] ))
92 $post_data['comment_status'] = 'closed';
94 if (!isset( $post_data['ping_status'] ))
95 $post_data['ping_status'] = 'closed';
97 foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
98 if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
99 $post_data['edit_date'] = '1';
104 if ( !empty( $post_data['edit_date'] ) ) {
105 $aa = $post_data['aa'];
106 $mm = $post_data['mm'];
107 $jj = $post_data['jj'];
108 $hh = $post_data['hh'];
109 $mn = $post_data['mn'];
110 $ss = $post_data['ss'];
111 $aa = ($aa <= 0 ) ? date('Y') : $aa;
112 $mm = ($mm <= 0 ) ? date('n') : $mm;
113 $jj = ($jj > 31 ) ? 31 : $jj;
114 $jj = ($jj <= 0 ) ? date('j') : $jj;
115 $hh = ($hh > 23 ) ? $hh -24 : $hh;
116 $mn = ($mn > 59 ) ? $mn -60 : $mn;
117 $ss = ($ss > 59 ) ? $ss -60 : $ss;
118 $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
119 $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
126 * Update an existing post with values provided in $_POST.
130 * @param array $post_data Optional.
131 * @return int Post ID.
133 function edit_post( $post_data = null ) {
135 if ( empty($post_data) )
136 $post_data = &$_POST;
138 $post_ID = (int) $post_data['post_ID'];
139 $post = get_post( $post_ID );
140 $post_data['post_type'] = $post->post_type;
141 $post_data['post_mime_type'] = $post->post_mime_type;
143 $ptype = get_post_type_object($post_data['post_type']);
144 if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
145 if ( 'page' == $post_data['post_type'] )
146 wp_die( __('You are not allowed to edit this page.' ));
148 wp_die( __('You are not allowed to edit this post.' ));
151 // Autosave shouldn't save too soon after a real save
152 if ( 'autosave' == $post_data['action'] ) {
153 $post =& get_post( $post_ID );
155 $then = strtotime($post->post_date_gmt . ' +0000');
156 $delta = AUTOSAVE_INTERVAL / 2;
157 if ( ($now - $then) < $delta )
161 $post_data = _wp_translate_postdata( true, $post_data );
162 if ( is_wp_error($post_data) )
163 wp_die( $post_data->get_error_message() );
164 if ( 'autosave' != $post_data['action'] && 'auto-draft' == $post_data['post_status'] )
165 $post_data['post_status'] = 'draft';
167 if ( isset($post_data['visibility']) ) {
168 switch ( $post_data['visibility'] ) {
170 $post_data['post_password'] = '';
173 unset( $post_data['sticky'] );
176 $post_data['post_status'] = 'private';
177 $post_data['post_password'] = '';
178 unset( $post_data['sticky'] );
184 if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) {
185 $formats = get_theme_support( 'post-formats' );
186 if ( is_array( $formats ) ) {
187 $formats = $formats[0];
188 if ( in_array( $post_data['post_format'], $formats ) ) {
189 set_post_format( $post_ID, $post_data['post_format'] );
190 } elseif ( '0' == $post_data['post_format'] ) {
191 set_post_format( $post_ID, false );
197 if ( isset($post_data['meta']) && $post_data['meta'] ) {
198 foreach ( $post_data['meta'] as $key => $value ) {
199 if ( !$meta = get_post_meta_by_id( $key ) )
201 if ( $meta->post_id != $post_ID )
203 if ( is_protected_meta( $value['key'] ) )
205 update_meta( $key, $value['key'], $value['value'] );
209 if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
210 foreach ( $post_data['deletemeta'] as $key => $value ) {
211 if ( !$meta = get_post_meta_by_id( $key ) )
213 if ( $meta->post_id != $post_ID )
215 if ( is_protected_meta( $meta->meta_key ) )
221 add_meta( $post_ID );
223 update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
225 wp_update_post( $post_data );
227 // Reunite any orphaned attachments with their parent
228 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
229 $draft_ids = array();
230 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
231 _relocate_children( $draft_temp_id, $post_ID );
233 // Now that we have an ID we can fix any attachment anchor hrefs
234 _fix_attachment_links( $post_ID );
236 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
238 if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
239 if ( ! empty( $post_data['sticky'] ) )
240 stick_post( $post_ID );
242 unstick_post( $post_ID );
249 * Process the post data for the bulk editing of posts.
251 * Updates all bulk edited posts/pages, adding (but not removing) tags and
252 * categories. Skips pages when they would be their own parent or child.
256 * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
259 function bulk_edit_posts( $post_data = null ) {
262 if ( empty($post_data) )
263 $post_data = &$_POST;
265 if ( isset($post_data['post_type']) )
266 $ptype = get_post_type_object($post_data['post_type']);
268 $ptype = get_post_type_object('post');
270 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
271 if ( 'page' == $ptype->name )
272 wp_die( __('You are not allowed to edit pages.'));
274 wp_die( __('You are not allowed to edit posts.'));
277 if ( -1 == $post_data['_status'] ) {
278 $post_data['post_status'] = null;
279 unset($post_data['post_status']);
281 $post_data['post_status'] = $post_data['_status'];
283 unset($post_data['_status']);
285 $post_IDs = array_map( 'intval', (array) $post_data['post'] );
287 $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
288 foreach ( $reset as $field ) {
289 if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
290 unset($post_data[$field]);
293 if ( isset($post_data['post_category']) ) {
294 if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
295 $new_cats = array_map( 'absint', $post_data['post_category'] );
297 unset($post_data['post_category']);
300 $tax_input = array();
301 if ( isset($post_data['tax_input'])) {
302 foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
305 if ( is_taxonomy_hierarchical( $tax_name ) )
306 $tax_input[$tax_name] = array_map( 'absint', $terms );
308 $tax_input[$tax_name] = preg_replace( '/\s*,\s*/', ',', rtrim( trim($terms), ' ,' ) );
309 $tax_input[$tax_name] = explode(',', $tax_input[$tax_name]);
314 if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
315 $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
318 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
319 $children[] = $parent;
321 foreach ( $pages as $page ) {
322 if ( $page->ID == $parent ) {
323 $parent = $page->post_parent;
330 $updated = $skipped = $locked = array();
331 foreach ( $post_IDs as $post_ID ) {
332 $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
334 if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
335 $skipped[] = $post_ID;
339 if ( wp_check_post_lock( $post_ID ) ) {
340 $locked[] = $post_ID;
344 $tax_names = get_object_taxonomies( get_post($post_ID) );
345 foreach ( $tax_names as $tax_name ) {
346 $taxonomy_obj = get_taxonomy($tax_name);
347 if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
348 $new_terms = $tax_input[$tax_name];
350 $new_terms = array();
352 if ( $taxonomy_obj->hierarchical )
353 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
355 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
357 $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
360 if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
361 $cats = (array) wp_get_post_categories($post_ID);
362 $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
363 unset( $post_data['tax_input']['category'] );
366 $post_data['ID'] = $post_ID;
367 $updated[] = wp_update_post( $post_data );
369 if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
370 if ( 'sticky' == $post_data['sticky'] )
371 stick_post( $post_ID );
373 unstick_post( $post_ID );
378 return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
382 * Default post information to use when populating the "Write Post" form.
386 * @param string $post_type A post type string, defaults to 'post'.
387 * @return object stdClass object containing all the default post data as attributes
389 function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
393 if ( !empty( $_REQUEST['post_title'] ) )
394 $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
397 if ( !empty( $_REQUEST['content'] ) )
398 $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
401 if ( !empty( $_REQUEST['excerpt'] ) )
402 $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
404 if ( $create_in_db ) {
405 // Cleanup old auto-drafts more than 7 days old
406 $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
407 foreach ( (array) $old_posts as $delete )
408 wp_delete_post( $delete, true ); // Force delete
409 $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
410 $post = get_post( $post_id );
411 if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
412 set_post_format( $post, get_option( 'default_post_format' ) );
415 $post->post_author = '';
416 $post->post_date = '';
417 $post->post_date_gmt = '';
418 $post->post_password = '';
419 $post->post_type = $post_type;
420 $post->post_status = 'draft';
423 $post->comment_status = get_option( 'default_comment_status' );
424 $post->ping_status = get_option( 'default_ping_status' );
425 $post->post_pingback = get_option( 'default_pingback_flag' );
426 $post->post_category = get_option( 'default_category' );
427 $post->page_template = 'default';
428 $post->post_parent = 0;
429 $post->menu_order = 0;
432 $post->post_content = apply_filters( 'default_content', $post_content, $post );
433 $post->post_title = apply_filters( 'default_title', $post_title, $post );
434 $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
435 $post->post_name = '';
441 * Get the default page information to use.
445 * @return object stdClass object containing all the default post data as attributes
447 function get_default_page_to_edit() {
448 $page = get_default_post_to_edit();
449 $page->post_type = 'page';
454 * Get an existing post and format it for editing.
458 * @param unknown_type $id
461 function get_post_to_edit( $id ) {
463 $post = get_post( $id, OBJECT, 'edit' );
465 if ( $post->post_type == 'page' )
466 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
472 * Determine if a post exists based on title, content, and date
476 * @param string $title Post title
477 * @param string $content Optional post content
478 * @param string $date Optional post date
479 * @return int Post ID if post exists, 0 otherwise.
481 function post_exists($title, $content = '', $date = '') {
484 $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
485 $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
486 $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
488 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
491 if ( !empty ( $date ) ) {
492 $query .= ' AND post_date = %s';
493 $args[] = $post_date;
496 if ( !empty ( $title ) ) {
497 $query .= ' AND post_title = %s';
498 $args[] = $post_title;
501 if ( !empty ( $content ) ) {
502 $query .= 'AND post_content = %s';
503 $args[] = $post_content;
506 if ( !empty ( $args ) )
507 return $wpdb->get_var( $wpdb->prepare($query, $args) );
513 * Creates a new post from the "Write Post" form using $_POST information.
519 function wp_write_post() {
523 if ( isset($_POST['post_type']) )
524 $ptype = get_post_type_object($_POST['post_type']);
526 $ptype = get_post_type_object('post');
528 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
529 if ( 'page' == $ptype->name )
530 return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
532 return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
535 $_POST['post_mime_type'] = '';
537 // Check for autosave collisions
538 // Does this need to be updated? ~ Mark
540 if ( isset($_POST['temp_ID']) ) {
541 $temp_id = (int) $_POST['temp_ID'];
542 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
543 $draft_ids = array();
544 foreach ( $draft_ids as $temp => $real )
545 if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
546 unset($draft_ids[$temp]);
548 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
549 $_POST['post_ID'] = $draft_ids[$temp_id];
550 unset($_POST['temp_ID']);
551 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
556 $translated = _wp_translate_postdata( false );
557 if ( is_wp_error($translated) )
560 if ( isset($_POST['visibility']) ) {
561 switch ( $_POST['visibility'] ) {
563 $_POST['post_password'] = '';
566 unset( $_POST['sticky'] );
569 $_POST['post_status'] = 'private';
570 $_POST['post_password'] = '';
571 unset( $_POST['sticky'] );
577 $post_ID = wp_insert_post( $_POST );
578 if ( is_wp_error( $post_ID ) )
581 if ( empty($post_ID) )
584 add_meta( $post_ID );
586 add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
588 // Reunite any orphaned attachments with their parent
589 // Does this need to be udpated? ~ Mark
590 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
591 $draft_ids = array();
592 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
593 _relocate_children( $draft_temp_id, $post_ID );
594 if ( $temp_id && $temp_id != $draft_temp_id )
595 _relocate_children( $temp_id, $post_ID );
597 // Update autosave collision detection
599 $draft_ids[$temp_id] = $post_ID;
600 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
603 // Now that we have an ID we can fix any attachment anchor hrefs
604 _fix_attachment_links( $post_ID );
606 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
612 * Calls wp_write_post() and handles the errors.
618 function write_post() {
619 $result = wp_write_post();
620 if ( is_wp_error( $result ) )
621 wp_die( $result->get_error_message() );
631 * {@internal Missing Short Description}}
635 * @param unknown_type $post_ID
638 function add_meta( $post_ID ) {
640 $post_ID = (int) $post_ID;
642 $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
643 $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
644 $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes_deep( $_POST['metavalue'] ) ) : '';
645 if ( is_string($metavalue) )
646 $metavalue = trim( $metavalue );
648 if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
649 // We have a key/value pair. If both the select and the
650 // input for the key have data, the input takes precedence:
652 if ('#NONE#' != $metakeyselect)
653 $metakey = $metakeyselect;
656 $metakey = $metakeyinput; // default
658 if ( is_protected_meta( $metakey ) )
661 wp_cache_delete($post_ID, 'post_meta');
662 $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) );
663 $meta_id = $wpdb->insert_id;
664 do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue );
672 * {@internal Missing Short Description}}
676 * @param unknown_type $mid
679 function delete_meta( $mid ) {
683 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
685 do_action( 'delete_postmeta', $mid );
686 wp_cache_delete($post_id, 'post_meta');
687 $rval = $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
688 do_action( 'deleted_postmeta', $mid );
694 * Get a list of previously defined keys.
700 function get_meta_keys() {
703 $keys = $wpdb->get_col( "
707 ORDER BY meta_key" );
713 * {@internal Missing Short Description}}
717 * @param unknown_type $mid
720 function get_post_meta_by_id( $mid ) {
724 $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
727 if ( is_serialized_string( $meta->meta_value ) )
728 $meta->meta_value = maybe_unserialize( $meta->meta_value );
733 * {@internal Missing Short Description}}
735 * Some postmeta stuff.
739 * @param unknown_type $postid
742 function has_meta( $postid ) {
745 return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
746 FROM $wpdb->postmeta WHERE post_id = %d
747 ORDER BY meta_key,meta_id", $postid), ARRAY_A );
752 * {@internal Missing Short Description}}
756 * @param unknown_type $meta_id
757 * @param unknown_type $meta_key Expect Slashed
758 * @param unknown_type $meta_value Expect Slashed
761 function update_meta( $meta_id, $meta_key, $meta_value ) {
764 $meta_key = stripslashes($meta_key);
766 if ( is_protected_meta( $meta_key ) )
769 if ( '' === trim( $meta_value ) )
772 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
774 $meta_value = maybe_serialize( stripslashes_deep( $meta_value ) );
775 $meta_id = (int) $meta_id;
777 $data = compact( 'meta_key', 'meta_value' );
778 $where = compact( 'meta_id' );
780 do_action( 'update_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
781 $rval = $wpdb->update( $wpdb->postmeta, $data, $where );
782 wp_cache_delete($post_id, 'post_meta');
783 do_action( 'updated_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
793 * Replace hrefs of attachment anchors with up-to-date permalinks.
798 * @param unknown_type $post_ID
801 function _fix_attachment_links( $post_ID ) {
802 global $_fix_attachment_link_id;
804 $post = & get_post( $post_ID, ARRAY_A );
806 $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
808 // See if we have any rel="attachment" links
809 if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
813 $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
814 foreach ( $anchor_matches[0] as $anchor ) {
815 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
818 $id = (int) $id_matches[3];
820 // While we have the attachment ID, let's adopt any orphans.
821 $attachment = & get_post( $id, ARRAY_A );
822 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
823 $attachment['post_parent'] = $post_ID;
824 // Escape data pulled from DB.
825 $attachment = add_magic_quotes( $attachment );
826 wp_update_post( $attachment );
829 $post_search[$i] = $anchor;
830 $_fix_attachment_link_id = $id;
831 $post_replace[$i] = preg_replace_callback( "#href=(\"|')[^'\"]*\\1#", '_fix_attachment_links_replace_cb', $anchor );
835 $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
837 // Escape data pulled from DB.
838 $post = add_magic_quotes( $post);
840 return wp_update_post( $post);
843 function _fix_attachment_links_replace_cb($match) {
844 global $_fix_attachment_link_id;
845 return stripslashes( 'href='.$match[1] ).get_attachment_link( $_fix_attachment_link_id ).stripslashes( $match[1] );
849 * Move child posts to a new parent.
854 * @param unknown_type $old_ID
855 * @param unknown_type $new_ID
858 function _relocate_children( $old_ID, $new_ID ) {
860 $old_ID = (int) $old_ID;
861 $new_ID = (int) $new_ID;
863 $children = $wpdb->get_col( $wpdb->prepare("
866 WHERE meta_key = '_wp_attachment_temp_parent'
867 AND meta_value = %d", $old_ID) );
869 foreach ( $children as $child_id ) {
870 $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
871 delete_post_meta($child_id, '_wp_attachment_temp_parent');
876 * Get all the possible statuses for a post_type
880 * @param string $type The post_type you want the statuses for
881 * @return array As array of all the statuses for the supplied post type
883 function get_available_post_statuses($type = 'post') {
884 $stati = wp_count_posts($type);
886 return array_keys(get_object_vars($stati));
890 * Run the wp query to fetch the posts for listing on the edit posts page
894 * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
897 function wp_edit_posts_query( $q = false ) {
900 $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
901 $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
902 $post_stati = get_post_stati();
904 if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
905 $post_type = $q['post_type'];
909 $avail_post_stati = get_available_post_statuses($post_type);
911 if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
912 $post_status = $q['post_status'];
916 if ( isset($q['orderby']) )
917 $orderby = $q['orderby'];
918 elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
919 $orderby = 'modified';
921 if ( isset($q['order']) )
922 $order = $q['order'];
923 elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
926 $per_page = 'edit_' . $post_type . '_per_page';
927 $posts_per_page = (int) get_user_option( $per_page );
928 if ( empty( $posts_per_page ) || $posts_per_page < 1 )
929 $posts_per_page = 20;
931 $posts_per_page = apply_filters( $per_page, $posts_per_page );
932 $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
934 $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
936 // Hierarchical types require special args.
937 if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
938 $query['orderby'] = 'menu_order title';
939 $query['order'] = 'asc';
940 $query['posts_per_page'] = -1;
941 $query['posts_per_archive_page'] = -1;
944 if ( ! empty( $q['show_sticky'] ) )
945 $query['post__in'] = (array) get_option( 'sticky_posts' );
949 return $avail_post_stati;
953 * Get default post mime types
959 function get_post_mime_types() {
960 $post_mime_types = array( // array( adj, noun )
961 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
962 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
963 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
966 return apply_filters('post_mime_types', $post_mime_types);
970 * {@internal Missing Short Description}}
974 * @param unknown_type $type
977 function get_available_post_mime_types($type = 'attachment') {
980 $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
985 * {@internal Missing Short Description}}
989 * @param unknown_type $q
992 function wp_edit_attachments_query( $q = false ) {
996 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
997 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
998 $q['post_type'] = 'attachment';
999 $post_type = get_post_type_object( 'attachment' );
1000 $states = array( 'inherit' );
1001 if ( current_user_can( $post_type->cap->read_private_posts ) )
1002 $states[] = 'private';
1004 $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
1005 $media_per_page = (int) get_user_option( 'upload_per_page' );
1006 if ( empty( $media_per_page ) || $media_per_page < 1 )
1007 $media_per_page = 20;
1008 $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
1010 $post_mime_types = get_post_mime_types();
1011 $avail_post_mime_types = get_available_post_mime_types('attachment');
1013 if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
1014 unset($q['post_mime_type']);
1016 if ( isset($q['detached']) )
1017 add_filter('posts_where', '_edit_attachments_query_helper');
1021 if ( isset($q['detached']) )
1022 remove_filter('posts_where', '_edit_attachments_query_helper');
1024 return array($post_mime_types, $avail_post_mime_types);
1027 function _edit_attachments_query_helper($where) {
1028 return $where .= ' AND post_parent < 1';
1032 * {@internal Missing Short Description}}
1034 * @uses get_user_option()
1037 * @param unknown_type $id
1038 * @param unknown_type $page
1041 function postbox_classes( $id, $page ) {
1042 if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id )
1045 if ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
1046 if ( !is_array( $closed ) ) {
1049 return in_array( $id, $closed )? 'closed' : '';
1056 * {@internal Missing Short Description}}
1060 * @param int|object $id Post ID or post object.
1061 * @param string $title (optional) Title
1062 * @param string $name (optional) Name
1063 * @return array With two entries of type string
1065 function get_sample_permalink($id, $title = null, $name = null) {
1066 $post = &get_post($id);
1068 return array('', '');
1070 $ptype = get_post_type_object($post->post_type);
1072 $original_status = $post->post_status;
1073 $original_date = $post->post_date;
1074 $original_name = $post->post_name;
1076 // Hack: get_permalink would return ugly permalink for
1077 // drafts, so we will fake, that our post is published
1078 if ( in_array($post->post_status, array('draft', 'pending')) ) {
1079 $post->post_status = 'publish';
1080 $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
1083 // If the user wants to set a new name -- override the current one
1084 // Note: if empty name is supplied -- use the title instead, see #6072
1085 if ( !is_null($name) )
1086 $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
1088 $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
1090 $post->filter = 'sample';
1092 $permalink = get_permalink($post, true);
1094 // Replace custom post_type Token with generic pagename token for ease of use.
1095 $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
1097 // Handle page hierarchy
1098 if ( $ptype->hierarchical ) {
1099 $uri = get_page_uri($post);
1100 $uri = untrailingslashit($uri);
1101 $uri = strrev( stristr( strrev( $uri ), '/' ) );
1102 $uri = untrailingslashit($uri);
1105 $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
1108 $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
1109 $post->post_status = $original_status;
1110 $post->post_date = $original_date;
1111 $post->post_name = $original_name;
1112 unset($post->filter);
1118 * sample permalink html
1120 * intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1124 * @param int|object $id Post ID or post object.
1125 * @param string $new_title (optional) New title
1126 * @param string $new_slug (optional) New slug
1127 * @return string intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1129 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
1131 $post = &get_post($id);
1133 list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
1135 if ( 'publish' == $post->post_status ) {
1136 $ptype = get_post_type_object($post->post_type);
1137 $view_post = $ptype->labels->view_item;
1138 $title = __('Click to edit this part of the permalink');
1140 $title = __('Temporary permalink. Click to edit this part.');
1143 if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
1144 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
1145 if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
1146 $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
1147 if ( isset($view_post) )
1148 $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
1150 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1155 if ( function_exists('mb_strlen') ) {
1156 if ( mb_strlen($post_name) > 30 ) {
1157 $post_name_abridged = mb_substr($post_name, 0, 14). '…' . mb_substr($post_name, -14);
1159 $post_name_abridged = $post_name;
1162 if ( strlen($post_name) > 30 ) {
1163 $post_name_abridged = substr($post_name, 0, 14). '…' . substr($post_name, -14);
1165 $post_name_abridged = $post_name;
1169 $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
1170 $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
1171 $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
1172 $return = '<strong>' . __('Permalink:') . "</strong>\n";
1173 $return .= '<span id="sample-permalink">' . $display_link . "</span>\n";
1174 $return .= '‎'; // Fix bi-directional text display defect in RTL languages.
1175 $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";
1176 $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
1177 if ( isset($view_post) )
1178 $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
1180 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1186 * Output HTML for the post thumbnail meta-box.
1190 * @param int $thumbnail_id ID of the attachment used for thumbnail
1191 * @return string html
1193 function _wp_post_thumbnail_html( $thumbnail_id = NULL ) {
1194 global $content_width, $_wp_additional_image_sizes, $post_ID;
1195 $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>';
1196 $content = sprintf($set_thumbnail_link, esc_html__( 'Set featured image' ));
1198 if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
1199 $old_content_width = $content_width;
1200 $content_width = 266;
1201 if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
1202 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
1204 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
1205 if ( !empty( $thumbnail_html ) ) {
1206 $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" );
1207 $content = sprintf($set_thumbnail_link, $thumbnail_html);
1208 $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>';
1210 $content_width = $old_content_width;
1213 return apply_filters( 'admin_post_thumbnail_html', $content );
1217 * Check to see if the post is currently being edited by another user.
1221 * @param int $post_id ID of the post to check for editing
1222 * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
1224 function wp_check_post_lock( $post_id ) {
1225 if ( !$post = get_post( $post_id ) )
1228 if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
1231 $lock = explode( ':', $lock );
1233 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1235 $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
1237 if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
1243 * Mark the post as currently being edited by the current user
1247 * @param int $post_id ID of the post to being edited
1248 * @return bool Returns false if the post doesn't exist of there is no current user
1250 function wp_set_post_lock( $post_id ) {
1251 if ( !$post = get_post( $post_id ) )
1253 if ( 0 == ($user_id = get_current_user_id()) )
1257 $lock = "$now:$user_id";
1259 update_post_meta( $post->ID, '_edit_lock', $lock );
1263 * Outputs the notice message to say that someone else is editing this post at the moment.
1268 function _admin_notice_post_locked() {
1271 $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
1272 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1273 $last_user = get_userdata( $user );
1274 $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
1276 switch ($post->post_type) {
1278 $message = __( 'Warning: %s is currently editing this post' );
1281 $message = __( 'Warning: %s is currently editing this page' );
1284 $message = __( 'Warning: %s is currently editing this.' );
1287 $message = sprintf( $message, esc_html( $last_user_name ) );
1288 echo "<div class='error'><p>$message</p></div>";
1292 * Creates autosave data for the specified post from $_POST data.
1294 * @package WordPress
1295 * @subpackage Post_Revisions
1298 * @uses _wp_translate_postdata()
1299 * @uses _wp_post_revision_fields()
1303 function wp_create_post_autosave( $post_id ) {
1304 $translated = _wp_translate_postdata( true );
1305 if ( is_wp_error( $translated ) )
1308 // Only store one autosave. If there is already an autosave, overwrite it.
1309 if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1310 $new_autosave = _wp_post_revision_fields( $_POST, true );
1311 $new_autosave['ID'] = $old_autosave->ID;
1312 $new_autosave['post_author'] = get_current_user_id();
1313 return wp_update_post( $new_autosave );
1316 // _wp_put_post_revision() expects unescaped.
1317 $_POST = stripslashes_deep($_POST);
1319 // Otherwise create the new autosave as a special post revision
1320 return _wp_put_post_revision( $_POST, true );
1324 * Save draft or manually autosave for showing preview.
1326 * @package WordPress
1329 * @uses wp_write_post()
1332 * @uses current_user_can()
1333 * @uses wp_create_post_autosave()
1335 * @return str URL to redirect to show the preview
1337 function post_preview() {
1339 $post_ID = (int) $_POST['post_ID'];
1340 $status = get_post_status( $post_ID );
1341 if ( 'auto-draft' == $status )
1342 wp_die( __('Preview not available. Please save as a draft first.') );
1344 if ( isset($_POST['catslist']) )
1345 $_POST['post_category'] = explode(",", $_POST['catslist']);
1347 if ( isset($_POST['tags_input']) )
1348 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1350 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1351 unset($_POST['post_category']);
1353 $_POST['ID'] = $post_ID;
1354 $post = get_post($post_ID);
1356 if ( 'page' == $post->post_type ) {
1357 if ( !current_user_can('edit_page', $post_ID) )
1358 wp_die(__('You are not allowed to edit this page.'));
1360 if ( !current_user_can('edit_post', $post_ID) )
1361 wp_die(__('You are not allowed to edit this post.'));
1364 if ( 'draft' == $post->post_status ) {
1366 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
1367 $id = wp_create_post_autosave( $post->ID );
1368 if ( ! is_wp_error($id) )
1372 if ( is_wp_error($id) )
1373 wp_die( $id->get_error_message() );
1375 if ( $_POST['post_status'] == 'draft' ) {
1376 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1378 $nonce = wp_create_nonce('post_preview_' . $id);
1379 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1386 * Adds the TinyMCE editor used on the Write and Edit screens.
1388 * @package WordPress
1391 * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
1392 * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
1393 * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
1394 * to the URL when queueing them with the mce_external_plugins filter.
1396 * @param bool $teeny optional Output a trimmed down version used in Press This.
1397 * @param mixed $settings optional An array that can add to or overwrite the default TinyMCE settings.
1399 function wp_tiny_mce( $teeny = false, $settings = false ) {
1400 global $concatenate_scripts, $compress_scripts, $tinymce_version, $editor_styles;
1402 if ( ! user_can_richedit() )
1405 $baseurl = includes_url('js/tinymce');
1407 $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1410 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1411 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1412 The + sign marks the default language. More information:
1413 http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1415 $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');
1418 $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs') );
1421 $plugins = array( 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus', 'wplink', 'wpdialogs' );
1424 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1425 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1426 The url should be absolute and should include the js file name to be loaded. Example:
1427 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1428 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1430 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1433 if ( ! empty($mce_external_plugins) ) {
1436 The following filter loads external language files for TinyMCE plugins.
1437 It takes an associative array 'plugin_name' => 'path', where path is the
1438 include path to the file. The language file should follow the same format as
1439 /tinymce/langs/wp-langs.php and should define a variable $strings that
1440 holds all translated strings.
1441 When this filter is not used, the function will try to load {mce_locale}.js.
1442 If that is not found, en.js will be tried next.
1444 $mce_external_languages = apply_filters('mce_external_languages', array());
1446 $loaded_langs = array();
1449 if ( ! empty($mce_external_languages) ) {
1450 foreach ( $mce_external_languages as $name => $path ) {
1451 if ( @is_file($path) && @is_readable($path) ) {
1452 include_once($path);
1453 $ext_plugins .= $strings . "\n";
1454 $loaded_langs[] = $name;
1459 foreach ( $mce_external_plugins as $name => $url ) {
1461 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1463 $plugins[] = '-' . $name;
1465 $plugurl = dirname($url);
1466 $strings = $str1 = $str2 = '';
1467 if ( ! in_array($name, $loaded_langs) ) {
1468 $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1469 $path = WP_PLUGIN_DIR . $path . '/langs/';
1471 if ( function_exists('realpath') )
1472 $path = trailingslashit( realpath($path) );
1474 if ( @is_file($path . $mce_locale . '.js') )
1475 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1477 if ( @is_file($path . $mce_locale . '_dlg.js') )
1478 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1480 if ( 'en' != $mce_locale && empty($strings) ) {
1481 if ( @is_file($path . 'en.js') ) {
1482 $str1 = @file_get_contents($path . 'en.js');
1483 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1486 if ( @is_file($path . 'en_dlg.js') ) {
1487 $str2 = @file_get_contents($path . 'en_dlg.js');
1488 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1492 if ( ! empty($strings) )
1493 $ext_plugins .= "\n" . $strings . "\n";
1496 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1497 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1503 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1504 $mce_buttons = implode($mce_buttons, ',');
1505 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1507 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1508 $mce_buttons = implode($mce_buttons, ',');
1510 $mce_buttons_2 = array( 'formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' );
1511 $mce_buttons_2 = apply_filters('mce_buttons_2', $mce_buttons_2);
1512 $mce_buttons_2 = implode($mce_buttons_2, ',');
1514 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1515 $mce_buttons_3 = implode($mce_buttons_3, ',');
1517 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1518 $mce_buttons_4 = implode($mce_buttons_4, ',');
1520 $no_captions = (bool) apply_filters( 'disable_captions', '' );
1522 // TinyMCE init settings
1523 $initArray = array (
1524 'mode' => 'specific_textareas',
1525 'editor_selector' => 'theEditor',
1527 'theme' => 'advanced',
1528 'skin' => 'wp_theme',
1529 'theme_advanced_buttons1' => $mce_buttons,
1530 'theme_advanced_buttons2' => $mce_buttons_2,
1531 'theme_advanced_buttons3' => $mce_buttons_3,
1532 'theme_advanced_buttons4' => $mce_buttons_4,
1533 'language' => $mce_locale,
1534 'spellchecker_languages' => $mce_spellchecker_languages,
1535 'theme_advanced_toolbar_location' => 'top',
1536 'theme_advanced_toolbar_align' => 'left',
1537 'theme_advanced_statusbar_location' => 'bottom',
1538 'theme_advanced_resizing' => true,
1539 'theme_advanced_resize_horizontal' => false,
1540 'dialog_type' => 'modal',
1543 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
1544 {selector : 'img,table', classes : 'alignleft'}
1547 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
1548 {selector : 'img,table', classes : 'aligncenter'}
1551 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
1552 {selector : 'img,table', classes : 'alignright'}
1554 strikethrough : {inline : 'del'}
1556 'relative_urls' => false,
1557 'remove_script_host' => false,
1558 'convert_urls' => false,
1559 'apply_source_formatting' => false,
1560 'remove_linebreaks' => true,
1561 'gecko_spellcheck' => true,
1562 'entities' => '38,amp,60,lt,62,gt',
1563 'accessibility_focus' => true,
1564 'tabfocus_elements' => 'major-publishing-actions',
1565 'media_strict' => false,
1566 'paste_remove_styles' => true,
1567 'paste_remove_spans' => true,
1568 'paste_strip_class_attributes' => 'all',
1569 'paste_text_use_dialog' => true,
1570 'wpeditimage_disable_captions' => $no_captions,
1571 'plugins' => implode( ',', $plugins ),
1574 if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
1576 $style_uri = get_stylesheet_directory_uri();
1577 if ( ! is_child_theme() ) {
1578 foreach ( $editor_styles as $file )
1579 $mce_css[] = "$style_uri/$file";
1581 $style_dir = get_stylesheet_directory();
1582 $template_uri = get_template_directory_uri();
1583 $template_dir = get_template_directory();
1584 foreach ( $editor_styles as $file ) {
1585 if ( file_exists( "$template_dir/$file" ) )
1586 $mce_css[] = "$template_uri/$file";
1587 if ( file_exists( "$style_dir/$file" ) )
1588 $mce_css[] = "$style_uri/$file";
1591 $mce_css = implode( ',', $mce_css );
1596 $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
1598 if ( ! empty($mce_css) )
1599 $initArray['content_css'] = $mce_css;
1601 if ( is_array($settings) )
1602 $initArray = array_merge($initArray, $settings);
1604 // For people who really REALLY know what they're doing with TinyMCE
1605 // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1606 // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1607 // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1609 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1611 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1614 if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1615 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1616 $initArray['theme_advanced_buttons4'] = '';
1619 if ( ! isset($concatenate_scripts) )
1620 script_concat_settings();
1622 $language = $initArray['language'];
1624 $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1625 && false !== strpos( strtolower($_SERVER['HTTP_ACCEPT_ENCODING']), 'gzip');
1630 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1631 * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1632 * 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).
1634 $version = apply_filters('tiny_mce_version', '');
1635 $version = 'ver=' . $tinymce_version . $version;
1637 if ( 'en' != $language )
1638 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1641 foreach ( $initArray as $k => $v ) {
1642 if ( is_bool($v) ) {
1643 $val = $v ? 'true' : 'false';
1644 $mce_options .= $k . ':' . $val . ', ';
1646 } elseif ( !empty($v) && is_string($v) && ( '{' == $v{0} || '[' == $v{0} ) ) {
1647 $mce_options .= $k . ':' . $v . ', ';
1651 $mce_options .= $k . ':"' . $v . '", ';
1654 $mce_options = rtrim( trim($mce_options), '\n\r,' ); ?>
1656 <script type="text/javascript">
1659 base : "<?php echo $baseurl; ?>",
1661 query : "<?php echo $version; ?>",
1662 mceInit : {<?php echo $mce_options; ?>},
1663 load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1670 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=1&$version'></script>\n";
1672 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1674 if ( 'en' != $language && isset($lang) )
1675 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1677 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1680 <script type="text/javascript">
1684 echo "$ext_plugins\n";
1686 if ( ! $compressed ) {
1688 (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');}});})();
1690 tinyMCE.init(tinyMCEPreInit.mceInit);
1695 // Load additional inline scripts based on active plugins.
1696 if ( in_array( 'wpdialogs', $plugins ) ) {
1697 wp_print_scripts( array( 'wpdialogs-popup' ) );
1698 wp_print_styles('wp-jquery-ui-dialog');
1700 if ( in_array( 'wplink', $plugins ) ) {
1701 require_once ABSPATH . 'wp-admin/includes/internal-linking.php';
1702 add_action('tiny_mce_preload_dialogs', 'wp_link_dialog');
1703 wp_print_scripts('wplink');
1704 wp_print_styles('wplink');
1707 function wp_tiny_mce_preload_dialogs() { ?>
1708 <div id="preloaded-dialogs" style="display:none;">
1709 <?php do_action('tiny_mce_preload_dialogs'); ?>