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;
142 $ptype = get_post_type_object($post_data['post_type']);
143 if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
144 if ( 'page' == $post_data['post_type'] )
145 wp_die( __('You are not allowed to edit this page.' ));
147 wp_die( __('You are not allowed to edit this post.' ));
150 // Autosave shouldn't save too soon after a real save
151 if ( 'autosave' == $post_data['action'] ) {
152 $post =& get_post( $post_ID );
154 $then = strtotime($post->post_date_gmt . ' +0000');
155 $delta = AUTOSAVE_INTERVAL / 2;
156 if ( ($now - $then) < $delta )
160 $post_data = _wp_translate_postdata( true, $post_data );
161 if ( is_wp_error($post_data) )
162 wp_die( $post_data->get_error_message() );
163 if ( 'autosave' != $post_data['action'] && 'auto-draft' == $post_data['post_status'] )
164 $post_data['post_status'] = 'draft';
166 if ( isset($post_data['visibility']) ) {
167 switch ( $post_data['visibility'] ) {
169 $post_data['post_password'] = '';
172 unset( $post_data['sticky'] );
175 $post_data['post_status'] = 'private';
176 $post_data['post_password'] = '';
177 unset( $post_data['sticky'] );
183 if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) {
184 $formats = get_theme_support( 'post-formats' );
185 if ( is_array( $formats ) ) {
186 $formats = $formats[0];
187 if ( in_array( $post_data['post_format'], $formats ) ) {
188 set_post_format( $post_ID, $post_data['post_format'] );
189 } elseif ( '0' == $post_data['post_format'] ) {
190 set_post_format( $post_ID, false );
196 if ( isset($post_data['meta']) && $post_data['meta'] ) {
197 foreach ( $post_data['meta'] as $key => $value ) {
198 if ( !$meta = get_post_meta_by_id( $key ) )
200 if ( $meta->post_id != $post_ID )
202 update_meta( $key, $value['key'], $value['value'] );
206 if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
207 foreach ( $post_data['deletemeta'] as $key => $value ) {
208 if ( !$meta = get_post_meta_by_id( $key ) )
210 if ( $meta->post_id != $post_ID )
216 add_meta( $post_ID );
218 update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
220 wp_update_post( $post_data );
222 // Reunite any orphaned attachments with their parent
223 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
224 $draft_ids = array();
225 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
226 _relocate_children( $draft_temp_id, $post_ID );
228 // Now that we have an ID we can fix any attachment anchor hrefs
229 _fix_attachment_links( $post_ID );
231 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
233 if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
234 if ( ! empty( $post_data['sticky'] ) )
235 stick_post( $post_ID );
237 unstick_post( $post_ID );
244 * Process the post data for the bulk editing of posts.
246 * Updates all bulk edited posts/pages, adding (but not removing) tags and
247 * categories. Skips pages when they would be their own parent or child.
251 * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
254 function bulk_edit_posts( $post_data = null ) {
257 if ( empty($post_data) )
258 $post_data = &$_POST;
260 if ( isset($post_data['post_type']) )
261 $ptype = get_post_type_object($post_data['post_type']);
263 $ptype = get_post_type_object('post');
265 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
266 if ( 'page' == $ptype->name )
267 wp_die( __('You are not allowed to edit pages.'));
269 wp_die( __('You are not allowed to edit posts.'));
272 if ( -1 == $post_data['_status'] ) {
273 $post_data['post_status'] = null;
274 unset($post_data['post_status']);
276 $post_data['post_status'] = $post_data['_status'];
278 unset($post_data['_status']);
280 $post_IDs = array_map( 'intval', (array) $post_data['post'] );
282 $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
283 foreach ( $reset as $field ) {
284 if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
285 unset($post_data[$field]);
288 if ( isset($post_data['post_category']) ) {
289 if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
290 $new_cats = array_map( 'absint', $post_data['post_category'] );
292 unset($post_data['post_category']);
295 $tax_input = array();
296 if ( isset($post_data['tax_input'])) {
297 foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
300 if ( is_taxonomy_hierarchical( $tax_name ) )
301 $tax_input[$tax_name] = array_map( 'absint', $terms );
303 $tax_input[$tax_name] = preg_replace( '/\s*,\s*/', ',', rtrim( trim($terms), ' ,' ) );
304 $tax_input[$tax_name] = explode(',', $tax_input[$tax_name]);
309 if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
310 $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
313 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
314 $children[] = $parent;
316 foreach ( $pages as $page ) {
317 if ( $page->ID == $parent ) {
318 $parent = $page->post_parent;
325 $updated = $skipped = $locked = array();
326 foreach ( $post_IDs as $post_ID ) {
327 $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
329 if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
330 $skipped[] = $post_ID;
334 if ( wp_check_post_lock( $post_ID ) ) {
335 $locked[] = $post_ID;
339 $tax_names = get_object_taxonomies( get_post($post_ID) );
340 foreach ( $tax_names as $tax_name ) {
341 $taxonomy_obj = get_taxonomy($tax_name);
342 if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
343 $new_terms = $tax_input[$tax_name];
345 $new_terms = array();
347 if ( $taxonomy_obj->hierarchical )
348 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
350 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
352 $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
355 if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
356 $cats = (array) wp_get_post_categories($post_ID);
357 $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
358 unset( $post_data['tax_input']['category'] );
361 $post_data['ID'] = $post_ID;
362 $updated[] = wp_update_post( $post_data );
364 if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
365 if ( 'sticky' == $post_data['sticky'] )
366 stick_post( $post_ID );
368 unstick_post( $post_ID );
373 return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
377 * Default post information to use when populating the "Write Post" form.
381 * @param string $post_type A post type string, defaults to 'post'.
382 * @return object stdClass object containing all the default post data as attributes
384 function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
388 if ( !empty( $_REQUEST['post_title'] ) )
389 $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
392 if ( !empty( $_REQUEST['content'] ) )
393 $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
396 if ( !empty( $_REQUEST['excerpt'] ) )
397 $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
399 if ( $create_in_db ) {
400 // Cleanup old auto-drafts more than 7 days old
401 $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
402 foreach ( (array) $old_posts as $delete )
403 wp_delete_post( $delete, true ); // Force delete
404 $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
405 $post = get_post( $post_id );
406 if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
407 set_post_format( $post, get_option( 'default_post_format' ) );
410 $post->post_author = '';
411 $post->post_date = '';
412 $post->post_date_gmt = '';
413 $post->post_password = '';
414 $post->post_type = $post_type;
415 $post->post_status = 'draft';
418 $post->comment_status = get_option( 'default_comment_status' );
419 $post->ping_status = get_option( 'default_ping_status' );
420 $post->post_pingback = get_option( 'default_pingback_flag' );
421 $post->post_category = get_option( 'default_category' );
422 $post->page_template = 'default';
423 $post->post_parent = 0;
424 $post->menu_order = 0;
427 $post->post_content = apply_filters( 'default_content', $post_content, $post );
428 $post->post_title = apply_filters( 'default_title', $post_title, $post );
429 $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
430 $post->post_name = '';
436 * Get the default page information to use.
440 * @return object stdClass object containing all the default post data as attributes
442 function get_default_page_to_edit() {
443 $page = get_default_post_to_edit();
444 $page->post_type = 'page';
449 * Get an existing post and format it for editing.
453 * @param unknown_type $id
456 function get_post_to_edit( $id ) {
458 $post = get_post( $id, OBJECT, 'edit' );
460 if ( $post->post_type == 'page' )
461 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
467 * Determine if a post exists based on title, content, and date
471 * @param string $title Post title
472 * @param string $content Optional post content
473 * @param string $date Optional post date
474 * @return int Post ID if post exists, 0 otherwise.
476 function post_exists($title, $content = '', $date = '') {
479 $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
480 $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
481 $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
483 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
486 if ( !empty ( $date ) ) {
487 $query .= ' AND post_date = %s';
488 $args[] = $post_date;
491 if ( !empty ( $title ) ) {
492 $query .= ' AND post_title = %s';
493 $args[] = $post_title;
496 if ( !empty ( $content ) ) {
497 $query .= 'AND post_content = %s';
498 $args[] = $post_content;
501 if ( !empty ( $args ) )
502 return $wpdb->get_var( $wpdb->prepare($query, $args) );
508 * Creates a new post from the "Write Post" form using $_POST information.
514 function wp_write_post() {
518 if ( isset($_POST['post_type']) )
519 $ptype = get_post_type_object($_POST['post_type']);
521 $ptype = get_post_type_object('post');
523 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
524 if ( 'page' == $ptype->name )
525 return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
527 return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
530 // Check for autosave collisions
531 // Does this need to be updated? ~ Mark
533 if ( isset($_POST['temp_ID']) ) {
534 $temp_id = (int) $_POST['temp_ID'];
535 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
536 $draft_ids = array();
537 foreach ( $draft_ids as $temp => $real )
538 if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
539 unset($draft_ids[$temp]);
541 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
542 $_POST['post_ID'] = $draft_ids[$temp_id];
543 unset($_POST['temp_ID']);
544 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
549 $translated = _wp_translate_postdata( false );
550 if ( is_wp_error($translated) )
553 if ( isset($_POST['visibility']) ) {
554 switch ( $_POST['visibility'] ) {
556 $_POST['post_password'] = '';
559 unset( $_POST['sticky'] );
562 $_POST['post_status'] = 'private';
563 $_POST['post_password'] = '';
564 unset( $_POST['sticky'] );
570 $post_ID = wp_insert_post( $_POST );
571 if ( is_wp_error( $post_ID ) )
574 if ( empty($post_ID) )
577 add_meta( $post_ID );
579 add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
581 // Reunite any orphaned attachments with their parent
582 // Does this need to be udpated? ~ Mark
583 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
584 $draft_ids = array();
585 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
586 _relocate_children( $draft_temp_id, $post_ID );
587 if ( $temp_id && $temp_id != $draft_temp_id )
588 _relocate_children( $temp_id, $post_ID );
590 // Update autosave collision detection
592 $draft_ids[$temp_id] = $post_ID;
593 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
596 // Now that we have an ID we can fix any attachment anchor hrefs
597 _fix_attachment_links( $post_ID );
599 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
605 * Calls wp_write_post() and handles the errors.
611 function write_post() {
612 $result = wp_write_post();
613 if ( is_wp_error( $result ) )
614 wp_die( $result->get_error_message() );
624 * {@internal Missing Short Description}}
628 * @param unknown_type $post_ID
631 function add_meta( $post_ID ) {
633 $post_ID = (int) $post_ID;
635 $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
637 $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
638 $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
639 $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes_deep( $_POST['metavalue'] ) ) : '';
640 if ( is_string($metavalue) )
641 $metavalue = trim( $metavalue );
643 if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
644 // We have a key/value pair. If both the select and the
645 // input for the key have data, the input takes precedence:
647 if ('#NONE#' != $metakeyselect)
648 $metakey = $metakeyselect;
651 $metakey = $metakeyinput; // default
653 if ( in_array($metakey, $protected) )
656 wp_cache_delete($post_ID, 'post_meta');
657 $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) );
658 $meta_id = $wpdb->insert_id;
659 do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue );
667 * {@internal Missing Short Description}}
671 * @param unknown_type $mid
674 function delete_meta( $mid ) {
678 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
680 do_action( 'delete_postmeta', $mid );
681 wp_cache_delete($post_id, 'post_meta');
682 $rval = $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
683 do_action( 'deleted_postmeta', $mid );
689 * Get a list of previously defined keys.
695 function get_meta_keys() {
698 $keys = $wpdb->get_col( "
702 ORDER BY meta_key" );
708 * {@internal Missing Short Description}}
712 * @param unknown_type $mid
715 function get_post_meta_by_id( $mid ) {
719 $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
722 if ( is_serialized_string( $meta->meta_value ) )
723 $meta->meta_value = maybe_unserialize( $meta->meta_value );
728 * {@internal Missing Short Description}}
730 * Some postmeta stuff.
734 * @param unknown_type $postid
737 function has_meta( $postid ) {
740 return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
741 FROM $wpdb->postmeta WHERE post_id = %d
742 ORDER BY meta_key,meta_id", $postid), ARRAY_A );
747 * {@internal Missing Short Description}}
751 * @param unknown_type $meta_id
752 * @param unknown_type $meta_key Expect Slashed
753 * @param unknown_type $meta_value Expect Slashed
756 function update_meta( $meta_id, $meta_key, $meta_value ) {
759 $protected = array( '_wp_attached_file', '_wp_attachment_metadata', '_wp_old_slug', '_wp_page_template' );
761 $meta_key = stripslashes($meta_key);
763 if ( in_array($meta_key, $protected) )
766 if ( '' === trim( $meta_value ) )
769 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
771 $meta_value = maybe_serialize( stripslashes_deep( $meta_value ) );
772 $meta_id = (int) $meta_id;
774 $data = compact( 'meta_key', 'meta_value' );
775 $where = compact( 'meta_id' );
777 do_action( 'update_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
778 $rval = $wpdb->update( $wpdb->postmeta, $data, $where );
779 wp_cache_delete($post_id, 'post_meta');
780 do_action( 'updated_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
790 * Replace hrefs of attachment anchors with up-to-date permalinks.
795 * @param unknown_type $post_ID
798 function _fix_attachment_links( $post_ID ) {
799 global $_fix_attachment_link_id;
801 $post = & get_post( $post_ID, ARRAY_A );
803 $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
805 // See if we have any rel="attachment" links
806 if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
810 $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
811 foreach ( $anchor_matches[0] as $anchor ) {
812 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
815 $id = (int) $id_matches[3];
817 // While we have the attachment ID, let's adopt any orphans.
818 $attachment = & get_post( $id, ARRAY_A );
819 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
820 $attachment['post_parent'] = $post_ID;
821 // Escape data pulled from DB.
822 $attachment = add_magic_quotes( $attachment );
823 wp_update_post( $attachment );
826 $post_search[$i] = $anchor;
827 $_fix_attachment_link_id = $id;
828 $post_replace[$i] = preg_replace_callback( "#href=(\"|')[^'\"]*\\1#", '_fix_attachment_links_replace_cb', $anchor );
832 $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
834 // Escape data pulled from DB.
835 $post = add_magic_quotes( $post);
837 return wp_update_post( $post);
840 function _fix_attachment_links_replace_cb($match) {
841 global $_fix_attachment_link_id;
842 return stripslashes( 'href='.$match[1] ).get_attachment_link( $_fix_attachment_link_id ).stripslashes( $match[1] );
846 * Move child posts to a new parent.
851 * @param unknown_type $old_ID
852 * @param unknown_type $new_ID
855 function _relocate_children( $old_ID, $new_ID ) {
857 $old_ID = (int) $old_ID;
858 $new_ID = (int) $new_ID;
860 $children = $wpdb->get_col( $wpdb->prepare("
863 WHERE meta_key = '_wp_attachment_temp_parent'
864 AND meta_value = %d", $old_ID) );
866 foreach ( $children as $child_id ) {
867 $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
868 delete_post_meta($child_id, '_wp_attachment_temp_parent');
873 * Get all the possible statuses for a post_type
877 * @param string $type The post_type you want the statuses for
878 * @return array As array of all the statuses for the supplied post type
880 function get_available_post_statuses($type = 'post') {
881 $stati = wp_count_posts($type);
883 return array_keys(get_object_vars($stati));
887 * Run the wp query to fetch the posts for listing on the edit posts page
891 * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
894 function wp_edit_posts_query( $q = false ) {
897 $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
898 $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
899 $post_stati = get_post_stati();
901 if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
902 $post_type = $q['post_type'];
906 $avail_post_stati = get_available_post_statuses($post_type);
908 if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
909 $post_status = $q['post_status'];
913 if ( isset($q['orderby']) )
914 $orderby = $q['orderby'];
915 elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
916 $orderby = 'modified';
918 if ( isset($q['order']) )
919 $order = $q['order'];
920 elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
923 $per_page = 'edit_' . $post_type . '_per_page';
924 $posts_per_page = (int) get_user_option( $per_page );
925 if ( empty( $posts_per_page ) || $posts_per_page < 1 )
926 $posts_per_page = 20;
928 $posts_per_page = apply_filters( $per_page, $posts_per_page );
929 $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
931 $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
933 // Hierarchical types require special args.
934 if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
935 $query['orderby'] = 'menu_order title';
936 $query['order'] = 'asc';
937 $query['posts_per_page'] = -1;
938 $query['posts_per_archive_page'] = -1;
941 if ( ! empty( $q['show_sticky'] ) )
942 $query['post__in'] = (array) get_option( 'sticky_posts' );
946 return $avail_post_stati;
950 * Get default post mime types
956 function get_post_mime_types() {
957 $post_mime_types = array( // array( adj, noun )
958 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
959 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
960 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
963 return apply_filters('post_mime_types', $post_mime_types);
967 * {@internal Missing Short Description}}
971 * @param unknown_type $type
974 function get_available_post_mime_types($type = 'attachment') {
977 $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
982 * {@internal Missing Short Description}}
986 * @param unknown_type $q
989 function wp_edit_attachments_query( $q = false ) {
993 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
994 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
995 $q['post_type'] = 'attachment';
996 $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : 'inherit';
997 $media_per_page = (int) get_user_option( 'upload_per_page' );
998 if ( empty( $media_per_page ) || $media_per_page < 1 )
999 $media_per_page = 20;
1000 $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
1002 $post_mime_types = get_post_mime_types();
1003 $avail_post_mime_types = get_available_post_mime_types('attachment');
1005 if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
1006 unset($q['post_mime_type']);
1008 if ( isset($q['detached']) )
1009 add_filter('posts_where', '_edit_attachments_query_helper');
1013 if ( isset($q['detached']) )
1014 remove_filter('posts_where', '_edit_attachments_query_helper');
1016 return array($post_mime_types, $avail_post_mime_types);
1019 function _edit_attachments_query_helper($where) {
1020 return $where .= ' AND post_parent < 1';
1024 * {@internal Missing Short Description}}
1026 * @uses get_user_option()
1029 * @param unknown_type $id
1030 * @param unknown_type $page
1033 function postbox_classes( $id, $page ) {
1034 if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id )
1037 if ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
1038 if ( !is_array( $closed ) ) {
1041 return in_array( $id, $closed )? 'closed' : '';
1048 * {@internal Missing Short Description}}
1052 * @param int|object $id Post ID or post object.
1053 * @param string $title (optional) Title
1054 * @param string $name (optional) Name
1055 * @return array With two entries of type string
1057 function get_sample_permalink($id, $title = null, $name = null) {
1058 $post = &get_post($id);
1060 return array('', '');
1062 $ptype = get_post_type_object($post->post_type);
1064 $original_status = $post->post_status;
1065 $original_date = $post->post_date;
1066 $original_name = $post->post_name;
1068 // Hack: get_permalink would return ugly permalink for
1069 // drafts, so we will fake, that our post is published
1070 if ( in_array($post->post_status, array('draft', 'pending')) ) {
1071 $post->post_status = 'publish';
1072 $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
1075 // If the user wants to set a new name -- override the current one
1076 // Note: if empty name is supplied -- use the title instead, see #6072
1077 if ( !is_null($name) )
1078 $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
1080 $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
1082 $post->filter = 'sample';
1084 $permalink = get_permalink($post, true);
1086 // Replace custom post_type Token with generic pagename token for ease of use.
1087 $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
1089 // Handle page hierarchy
1090 if ( $ptype->hierarchical ) {
1091 $uri = get_page_uri($post);
1092 $uri = untrailingslashit($uri);
1093 $uri = strrev( stristr( strrev( $uri ), '/' ) );
1094 $uri = untrailingslashit($uri);
1097 $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
1100 $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
1101 $post->post_status = $original_status;
1102 $post->post_date = $original_date;
1103 $post->post_name = $original_name;
1104 unset($post->filter);
1110 * sample permalink html
1112 * intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1116 * @param int|object $id Post ID or post object.
1117 * @param string $new_title (optional) New title
1118 * @param string $new_slug (optional) New slug
1119 * @return string intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1121 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
1123 $post = &get_post($id);
1125 list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
1127 if ( 'publish' == $post->post_status ) {
1128 $ptype = get_post_type_object($post->post_type);
1129 $view_post = $ptype->labels->view_item;
1130 $title = __('Click to edit this part of the permalink');
1132 $title = __('Temporary permalink. Click to edit this part.');
1135 if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
1136 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
1137 if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
1138 $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
1139 if ( isset($view_post) )
1140 $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
1142 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1147 if ( function_exists('mb_strlen') ) {
1148 if ( mb_strlen($post_name) > 30 ) {
1149 $post_name_abridged = mb_substr($post_name, 0, 14). '…' . mb_substr($post_name, -14);
1151 $post_name_abridged = $post_name;
1154 if ( strlen($post_name) > 30 ) {
1155 $post_name_abridged = substr($post_name, 0, 14). '…' . substr($post_name, -14);
1157 $post_name_abridged = $post_name;
1161 $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
1162 $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
1163 $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
1164 $return = '<strong>' . __('Permalink:') . "</strong>\n";
1165 $return .= '<span id="sample-permalink">' . $display_link . "</span>\n";
1166 $return .= '‎'; // Fix bi-directional text display defect in RTL languages.
1167 $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";
1168 $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
1169 if ( isset($view_post) )
1170 $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
1172 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1178 * Output HTML for the post thumbnail meta-box.
1182 * @param int $thumbnail_id ID of the attachment used for thumbnail
1183 * @return string html
1185 function _wp_post_thumbnail_html( $thumbnail_id = NULL ) {
1186 global $content_width, $_wp_additional_image_sizes, $post_ID;
1187 $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>';
1188 $content = sprintf($set_thumbnail_link, esc_html__( 'Set featured image' ));
1190 if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
1191 $old_content_width = $content_width;
1192 $content_width = 266;
1193 if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
1194 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
1196 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
1197 if ( !empty( $thumbnail_html ) ) {
1198 $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" );
1199 $content = sprintf($set_thumbnail_link, $thumbnail_html);
1200 $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>';
1202 $content_width = $old_content_width;
1205 return apply_filters( 'admin_post_thumbnail_html', $content );
1209 * Check to see if the post is currently being edited by another user.
1213 * @param int $post_id ID of the post to check for editing
1214 * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
1216 function wp_check_post_lock( $post_id ) {
1217 if ( !$post = get_post( $post_id ) )
1220 if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
1223 $lock = explode( ':', $lock );
1225 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1227 $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
1229 if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
1235 * Mark the post as currently being edited by the current user
1239 * @param int $post_id ID of the post to being edited
1240 * @return bool Returns false if the post doesn't exist of there is no current user
1242 function wp_set_post_lock( $post_id ) {
1243 if ( !$post = get_post( $post_id ) )
1245 if ( 0 == ($user_id = get_current_user_id()) )
1249 $lock = "$now:$user_id";
1251 update_post_meta( $post->ID, '_edit_lock', $lock );
1255 * Outputs the notice message to say that someone else is editing this post at the moment.
1260 function _admin_notice_post_locked() {
1263 $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
1264 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1265 $last_user = get_userdata( $user );
1266 $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
1268 switch ($post->post_type) {
1270 $message = __( 'Warning: %s is currently editing this post' );
1273 $message = __( 'Warning: %s is currently editing this page' );
1276 $message = __( 'Warning: %s is currently editing this.' );
1279 $message = sprintf( $message, esc_html( $last_user_name ) );
1280 echo "<div class='error'><p>$message</p></div>";
1284 * Creates autosave data for the specified post from $_POST data.
1286 * @package WordPress
1287 * @subpackage Post_Revisions
1290 * @uses _wp_translate_postdata()
1291 * @uses _wp_post_revision_fields()
1295 function wp_create_post_autosave( $post_id ) {
1296 $translated = _wp_translate_postdata( true );
1297 if ( is_wp_error( $translated ) )
1300 // Only store one autosave. If there is already an autosave, overwrite it.
1301 if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1302 $new_autosave = _wp_post_revision_fields( $_POST, true );
1303 $new_autosave['ID'] = $old_autosave->ID;
1304 $new_autosave['post_author'] = get_current_user_id();
1305 return wp_update_post( $new_autosave );
1308 // _wp_put_post_revision() expects unescaped.
1309 $_POST = stripslashes_deep($_POST);
1311 // Otherwise create the new autosave as a special post revision
1312 return _wp_put_post_revision( $_POST, true );
1316 * Save draft or manually autosave for showing preview.
1318 * @package WordPress
1321 * @uses wp_write_post()
1324 * @uses current_user_can()
1325 * @uses wp_create_post_autosave()
1327 * @return str URL to redirect to show the preview
1329 function post_preview() {
1331 $post_ID = (int) $_POST['post_ID'];
1332 $status = get_post_status( $post_ID );
1333 if ( 'auto-draft' == $status )
1334 wp_die( __('Preview not available. Please save as a draft first.') );
1336 if ( isset($_POST['catslist']) )
1337 $_POST['post_category'] = explode(",", $_POST['catslist']);
1339 if ( isset($_POST['tags_input']) )
1340 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1342 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1343 unset($_POST['post_category']);
1345 $_POST['ID'] = $post_ID;
1346 $post = get_post($post_ID);
1348 if ( 'page' == $post->post_type ) {
1349 if ( !current_user_can('edit_page', $post_ID) )
1350 wp_die(__('You are not allowed to edit this page.'));
1352 if ( !current_user_can('edit_post', $post_ID) )
1353 wp_die(__('You are not allowed to edit this post.'));
1356 if ( 'draft' == $post->post_status ) {
1358 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
1359 $id = wp_create_post_autosave( $post->ID );
1360 if ( ! is_wp_error($id) )
1364 if ( is_wp_error($id) )
1365 wp_die( $id->get_error_message() );
1367 if ( $_POST['post_status'] == 'draft' ) {
1368 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1370 $nonce = wp_create_nonce('post_preview_' . $id);
1371 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1378 * Adds the TinyMCE editor used on the Write and Edit screens.
1380 * @package WordPress
1383 * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
1384 * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
1385 * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
1386 * to the URL when queueing them with the mce_external_plugins filter.
1388 * @param bool $teeny optional Output a trimmed down version used in Press This.
1389 * @param mixed $settings optional An array that can add to or overwrite the default TinyMCE settings.
1391 function wp_tiny_mce( $teeny = false, $settings = false ) {
1392 global $concatenate_scripts, $compress_scripts, $tinymce_version, $editor_styles;
1394 if ( ! user_can_richedit() )
1397 $baseurl = includes_url('js/tinymce');
1399 $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1402 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1403 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1404 The + sign marks the default language. More information:
1405 http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1407 $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');
1410 $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs') );
1413 $plugins = array( 'inlinepopups', 'spellchecker', 'paste', 'wordpress', 'fullscreen', 'wpeditimage', 'wpgallery', 'tabfocus', 'wplink', 'wpdialogs' );
1416 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1417 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1418 The url should be absolute and should include the js file name to be loaded. Example:
1419 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1420 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1422 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1425 if ( ! empty($mce_external_plugins) ) {
1428 The following filter loads external language files for TinyMCE plugins.
1429 It takes an associative array 'plugin_name' => 'path', where path is the
1430 include path to the file. The language file should follow the same format as
1431 /tinymce/langs/wp-langs.php and should define a variable $strings that
1432 holds all translated strings.
1433 When this filter is not used, the function will try to load {mce_locale}.js.
1434 If that is not found, en.js will be tried next.
1436 $mce_external_languages = apply_filters('mce_external_languages', array());
1438 $loaded_langs = array();
1441 if ( ! empty($mce_external_languages) ) {
1442 foreach ( $mce_external_languages as $name => $path ) {
1443 if ( @is_file($path) && @is_readable($path) ) {
1444 include_once($path);
1445 $ext_plugins .= $strings . "\n";
1446 $loaded_langs[] = $name;
1451 foreach ( $mce_external_plugins as $name => $url ) {
1453 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1455 $plugins[] = '-' . $name;
1457 $plugurl = dirname($url);
1458 $strings = $str1 = $str2 = '';
1459 if ( ! in_array($name, $loaded_langs) ) {
1460 $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1461 $path = WP_PLUGIN_DIR . $path . '/langs/';
1463 if ( function_exists('realpath') )
1464 $path = trailingslashit( realpath($path) );
1466 if ( @is_file($path . $mce_locale . '.js') )
1467 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1469 if ( @is_file($path . $mce_locale . '_dlg.js') )
1470 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1472 if ( 'en' != $mce_locale && empty($strings) ) {
1473 if ( @is_file($path . 'en.js') ) {
1474 $str1 = @file_get_contents($path . 'en.js');
1475 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1478 if ( @is_file($path . 'en_dlg.js') ) {
1479 $str2 = @file_get_contents($path . 'en_dlg.js');
1480 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1484 if ( ! empty($strings) )
1485 $ext_plugins .= "\n" . $strings . "\n";
1488 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1489 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1495 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1496 $mce_buttons = implode($mce_buttons, ',');
1497 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1499 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1500 $mce_buttons = implode($mce_buttons, ',');
1502 $mce_buttons_2 = array( 'formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' );
1503 $mce_buttons_2 = apply_filters('mce_buttons_2', $mce_buttons_2);
1504 $mce_buttons_2 = implode($mce_buttons_2, ',');
1506 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1507 $mce_buttons_3 = implode($mce_buttons_3, ',');
1509 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1510 $mce_buttons_4 = implode($mce_buttons_4, ',');
1512 $no_captions = (bool) apply_filters( 'disable_captions', '' );
1514 // TinyMCE init settings
1515 $initArray = array (
1516 'mode' => 'specific_textareas',
1517 'editor_selector' => 'theEditor',
1519 'theme' => 'advanced',
1520 'skin' => 'wp_theme',
1521 'theme_advanced_buttons1' => $mce_buttons,
1522 'theme_advanced_buttons2' => $mce_buttons_2,
1523 'theme_advanced_buttons3' => $mce_buttons_3,
1524 'theme_advanced_buttons4' => $mce_buttons_4,
1525 'language' => $mce_locale,
1526 'spellchecker_languages' => $mce_spellchecker_languages,
1527 'theme_advanced_toolbar_location' => 'top',
1528 'theme_advanced_toolbar_align' => 'left',
1529 'theme_advanced_statusbar_location' => 'bottom',
1530 'theme_advanced_resizing' => true,
1531 'theme_advanced_resize_horizontal' => false,
1532 'dialog_type' => 'modal',
1535 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
1536 {selector : 'img,table', classes : 'alignleft'}
1539 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
1540 {selector : 'img,table', classes : 'aligncenter'}
1543 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
1544 {selector : 'img,table', classes : 'alignright'}
1546 strikethrough : {inline : 'del'}
1548 'relative_urls' => false,
1549 'remove_script_host' => false,
1550 'convert_urls' => false,
1551 'apply_source_formatting' => false,
1552 'remove_linebreaks' => true,
1553 'gecko_spellcheck' => true,
1554 'entities' => '38,amp,60,lt,62,gt',
1555 'accessibility_focus' => true,
1556 'tabfocus_elements' => 'major-publishing-actions',
1557 'media_strict' => false,
1558 'paste_remove_styles' => true,
1559 'paste_remove_spans' => true,
1560 'paste_strip_class_attributes' => 'all',
1561 'paste_text_use_dialog' => true,
1562 'wpeditimage_disable_captions' => $no_captions,
1563 'plugins' => implode( ',', $plugins ),
1566 if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
1568 $style_uri = get_stylesheet_directory_uri();
1569 if ( ! is_child_theme() ) {
1570 foreach ( $editor_styles as $file )
1571 $mce_css[] = "$style_uri/$file";
1573 $style_dir = get_stylesheet_directory();
1574 $template_uri = get_template_directory_uri();
1575 $template_dir = get_template_directory();
1576 foreach ( $editor_styles as $file ) {
1577 if ( file_exists( "$template_dir/$file" ) )
1578 $mce_css[] = "$template_uri/$file";
1579 if ( file_exists( "$style_dir/$file" ) )
1580 $mce_css[] = "$style_uri/$file";
1583 $mce_css = implode( ',', $mce_css );
1588 $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
1590 if ( ! empty($mce_css) )
1591 $initArray['content_css'] = $mce_css;
1593 if ( is_array($settings) )
1594 $initArray = array_merge($initArray, $settings);
1596 // For people who really REALLY know what they're doing with TinyMCE
1597 // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1598 // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1599 // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1601 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1603 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1606 if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1607 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1608 $initArray['theme_advanced_buttons4'] = '';
1611 if ( ! isset($concatenate_scripts) )
1612 script_concat_settings();
1614 $language = $initArray['language'];
1616 $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1617 && false !== strpos( strtolower($_SERVER['HTTP_ACCEPT_ENCODING']), 'gzip');
1622 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1623 * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1624 * 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).
1626 $version = apply_filters('tiny_mce_version', '');
1627 $version = 'ver=' . $tinymce_version . $version;
1629 if ( 'en' != $language )
1630 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1633 foreach ( $initArray as $k => $v ) {
1634 if ( is_bool($v) ) {
1635 $val = $v ? 'true' : 'false';
1636 $mce_options .= $k . ':' . $val . ', ';
1638 } elseif ( !empty($v) && is_string($v) && ( '{' == $v{0} || '[' == $v{0} ) ) {
1639 $mce_options .= $k . ':' . $v . ', ';
1643 $mce_options .= $k . ':"' . $v . '", ';
1646 $mce_options = rtrim( trim($mce_options), '\n\r,' ); ?>
1648 <script type="text/javascript">
1651 base : "<?php echo $baseurl; ?>",
1653 query : "<?php echo $version; ?>",
1654 mceInit : {<?php echo $mce_options; ?>},
1655 load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1662 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=1&$version'></script>\n";
1664 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1666 if ( 'en' != $language && isset($lang) )
1667 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1669 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1672 <script type="text/javascript">
1676 echo "$ext_plugins\n";
1678 if ( ! $compressed ) {
1680 (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');}});})();
1682 tinyMCE.init(tinyMCEPreInit.mceInit);
1687 // Load additional inline scripts based on active plugins.
1688 if ( in_array( 'wpdialogs', $plugins ) ) {
1689 wp_print_scripts( array( 'wpdialogs-popup' ) );
1690 wp_print_styles('wp-jquery-ui-dialog');
1692 if ( in_array( 'wplink', $plugins ) ) {
1693 require_once ABSPATH . 'wp-admin/includes/internal-linking.php';
1694 add_action('tiny_mce_preload_dialogs', 'wp_link_dialog');
1695 wp_print_scripts('wplink');
1696 wp_print_styles('wplink');
1699 function wp_tiny_mce_preload_dialogs() { ?>
1700 <div id="preloaded-dialogs" style="display:none;">
1701 <?php do_action('tiny_mce_preload_dialogs'); ?>