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'];
29 if ( isset( $post_data['content'] ) )
30 $post_data['post_content'] = $post_data['content'];
32 if ( isset( $post_data['excerpt'] ) )
33 $post_data['post_excerpt'] = $post_data['excerpt'];
35 if ( isset( $post_data['parent_id'] ) )
36 $post_data['post_parent'] = (int) $post_data['parent_id'];
38 if ( isset($post_data['trackback_url']) )
39 $post_data['to_ping'] = $post_data['trackback_url'];
41 if ( !isset($post_data['user_ID']) )
42 $post_data['user_ID'] = $GLOBALS['user_ID'];
44 if (!empty ( $post_data['post_author_override'] ) ) {
45 $post_data['post_author'] = (int) $post_data['post_author_override'];
47 if (!empty ( $post_data['post_author'] ) ) {
48 $post_data['post_author'] = (int) $post_data['post_author'];
50 $post_data['post_author'] = (int) $post_data['user_ID'];
54 $ptype = get_post_type_object( $post_data['post_type'] );
55 if ( isset($post_data['user_ID']) && ($post_data['post_author'] != $post_data['user_ID']) ) {
56 if ( !current_user_can( $ptype->cap->edit_others_posts ) ) {
57 if ( 'page' == $post_data['post_type'] ) {
58 return new WP_Error( 'edit_others_pages', $update ?
59 __( 'You are not allowed to edit pages as this user.' ) :
60 __( 'You are not allowed to create pages as this user.' )
63 return new WP_Error( 'edit_others_posts', $update ?
64 __( 'You are not allowed to edit posts as this user.' ) :
65 __( 'You are not allowed to post as this user.' )
71 // What to do based on which button they pressed
72 if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
73 $post_data['post_status'] = 'draft';
74 if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
75 $post_data['post_status'] = 'private';
76 if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
77 $post_data['post_status'] = 'publish';
78 if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
79 $post_data['post_status'] = 'draft';
80 if ( isset($post_data['pending']) && '' != $post_data['pending'] )
81 $post_data['post_status'] = 'pending';
83 if ( isset( $post_data['ID'] ) )
84 $post_id = $post_data['ID'];
87 $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
89 // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
90 // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
91 if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
92 if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
93 $post_data['post_status'] = 'pending';
95 if ( ! isset($post_data['post_status']) )
96 $post_data['post_status'] = $previous_status;
98 if (!isset( $post_data['comment_status'] ))
99 $post_data['comment_status'] = 'closed';
101 if (!isset( $post_data['ping_status'] ))
102 $post_data['ping_status'] = 'closed';
104 foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
105 if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
106 $post_data['edit_date'] = '1';
111 if ( !empty( $post_data['edit_date'] ) ) {
112 $aa = $post_data['aa'];
113 $mm = $post_data['mm'];
114 $jj = $post_data['jj'];
115 $hh = $post_data['hh'];
116 $mn = $post_data['mn'];
117 $ss = $post_data['ss'];
118 $aa = ($aa <= 0 ) ? date('Y') : $aa;
119 $mm = ($mm <= 0 ) ? date('n') : $mm;
120 $jj = ($jj > 31 ) ? 31 : $jj;
121 $jj = ($jj <= 0 ) ? date('j') : $jj;
122 $hh = ($hh > 23 ) ? $hh -24 : $hh;
123 $mn = ($mn > 59 ) ? $mn -60 : $mn;
124 $ss = ($ss > 59 ) ? $ss -60 : $ss;
125 $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
126 $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
133 * Update an existing post with values provided in $_POST.
137 * @param array $post_data Optional.
138 * @return int Post ID.
140 function edit_post( $post_data = null ) {
142 if ( empty($post_data) )
143 $post_data = &$_POST;
145 // Clear out any data in internal vars.
146 unset( $post_data['filter'] );
148 $post_ID = (int) $post_data['post_ID'];
149 $post = get_post( $post_ID );
150 $post_data['post_type'] = $post->post_type;
151 $post_data['post_mime_type'] = $post->post_mime_type;
153 $ptype = get_post_type_object($post_data['post_type']);
154 if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
155 if ( 'page' == $post_data['post_type'] )
156 wp_die( __('You are not allowed to edit this page.' ));
158 wp_die( __('You are not allowed to edit this post.' ));
161 // Autosave shouldn't save too soon after a real save
162 if ( 'autosave' == $post_data['action'] ) {
163 $post =& get_post( $post_ID );
165 $then = strtotime($post->post_date_gmt . ' +0000');
166 $delta = AUTOSAVE_INTERVAL / 2;
167 if ( ($now - $then) < $delta )
171 $post_data = _wp_translate_postdata( true, $post_data );
172 if ( is_wp_error($post_data) )
173 wp_die( $post_data->get_error_message() );
174 if ( 'autosave' != $post_data['action'] && 'auto-draft' == $post_data['post_status'] )
175 $post_data['post_status'] = 'draft';
177 if ( isset($post_data['visibility']) ) {
178 switch ( $post_data['visibility'] ) {
180 $post_data['post_password'] = '';
183 unset( $post_data['sticky'] );
186 $post_data['post_status'] = 'private';
187 $post_data['post_password'] = '';
188 unset( $post_data['sticky'] );
194 if ( current_theme_supports( 'post-formats' ) && isset( $post_data['post_format'] ) ) {
195 $formats = get_theme_support( 'post-formats' );
196 if ( is_array( $formats ) ) {
197 $formats = $formats[0];
198 if ( in_array( $post_data['post_format'], $formats ) ) {
199 set_post_format( $post_ID, $post_data['post_format'] );
200 } elseif ( '0' == $post_data['post_format'] ) {
201 set_post_format( $post_ID, false );
207 if ( isset($post_data['meta']) && $post_data['meta'] ) {
208 foreach ( $post_data['meta'] as $key => $value ) {
209 if ( !$meta = get_post_meta_by_id( $key ) )
211 if ( $meta->post_id != $post_ID )
213 if ( is_protected_meta( $value['key'] ) )
215 update_meta( $key, $value['key'], $value['value'] );
219 if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
220 foreach ( $post_data['deletemeta'] as $key => $value ) {
221 if ( !$meta = get_post_meta_by_id( $key ) )
223 if ( $meta->post_id != $post_ID )
225 if ( is_protected_meta( $meta->meta_key ) )
231 add_meta( $post_ID );
233 update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
235 wp_update_post( $post_data );
237 // Reunite any orphaned attachments with their parent
238 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
239 $draft_ids = array();
240 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
241 _relocate_children( $draft_temp_id, $post_ID );
243 // Now that we have an ID we can fix any attachment anchor hrefs
244 _fix_attachment_links( $post_ID );
246 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
248 if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
249 if ( ! empty( $post_data['sticky'] ) )
250 stick_post( $post_ID );
252 unstick_post( $post_ID );
259 * Process the post data for the bulk editing of posts.
261 * Updates all bulk edited posts/pages, adding (but not removing) tags and
262 * categories. Skips pages when they would be their own parent or child.
266 * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
269 function bulk_edit_posts( $post_data = null ) {
272 if ( empty($post_data) )
273 $post_data = &$_POST;
275 if ( isset($post_data['post_type']) )
276 $ptype = get_post_type_object($post_data['post_type']);
278 $ptype = get_post_type_object('post');
280 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
281 if ( 'page' == $ptype->name )
282 wp_die( __('You are not allowed to edit pages.'));
284 wp_die( __('You are not allowed to edit posts.'));
287 if ( -1 == $post_data['_status'] ) {
288 $post_data['post_status'] = null;
289 unset($post_data['post_status']);
291 $post_data['post_status'] = $post_data['_status'];
293 unset($post_data['_status']);
295 $post_IDs = array_map( 'intval', (array) $post_data['post'] );
297 $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
298 foreach ( $reset as $field ) {
299 if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
300 unset($post_data[$field]);
303 if ( isset($post_data['post_category']) ) {
304 if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
305 $new_cats = array_map( 'absint', $post_data['post_category'] );
307 unset($post_data['post_category']);
310 $tax_input = array();
311 if ( isset($post_data['tax_input'])) {
312 foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
315 if ( is_taxonomy_hierarchical( $tax_name ) )
316 $tax_input[$tax_name] = array_map( 'absint', $terms );
318 $tax_input[$tax_name] = preg_replace( '/\s*,\s*/', ',', rtrim( trim($terms), ' ,' ) );
319 $tax_input[$tax_name] = explode(',', $tax_input[$tax_name]);
324 if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
325 $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
328 for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
329 $children[] = $parent;
331 foreach ( $pages as $page ) {
332 if ( $page->ID == $parent ) {
333 $parent = $page->post_parent;
340 $updated = $skipped = $locked = array();
341 foreach ( $post_IDs as $post_ID ) {
342 $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
344 if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
345 $skipped[] = $post_ID;
349 if ( wp_check_post_lock( $post_ID ) ) {
350 $locked[] = $post_ID;
354 $post = get_post( $post_ID );
355 $tax_names = get_object_taxonomies( $post );
356 foreach ( $tax_names as $tax_name ) {
357 $taxonomy_obj = get_taxonomy($tax_name);
358 if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
359 $new_terms = $tax_input[$tax_name];
361 $new_terms = array();
363 if ( $taxonomy_obj->hierarchical )
364 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
366 $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
368 $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
371 if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
372 $cats = (array) wp_get_post_categories($post_ID);
373 $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
374 unset( $post_data['tax_input']['category'] );
377 $post_data['post_mime_type'] = $post->post_mime_type;
378 $post_data['guid'] = $post->guid;
380 $post_data['ID'] = $post_ID;
381 $updated[] = wp_update_post( $post_data );
383 if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
384 if ( 'sticky' == $post_data['sticky'] )
385 stick_post( $post_ID );
387 unstick_post( $post_ID );
392 return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
396 * Default post information to use when populating the "Write Post" form.
400 * @param string $post_type A post type string, defaults to 'post'.
401 * @return object stdClass object containing all the default post data as attributes
403 function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
407 if ( !empty( $_REQUEST['post_title'] ) )
408 $post_title = esc_html( stripslashes( $_REQUEST['post_title'] ));
411 if ( !empty( $_REQUEST['content'] ) )
412 $post_content = esc_html( stripslashes( $_REQUEST['content'] ));
415 if ( !empty( $_REQUEST['excerpt'] ) )
416 $post_excerpt = esc_html( stripslashes( $_REQUEST['excerpt'] ));
418 if ( $create_in_db ) {
419 // Cleanup old auto-drafts more than 7 days old
420 $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
421 foreach ( (array) $old_posts as $delete )
422 wp_delete_post( $delete, true ); // Force delete
423 $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
424 $post = get_post( $post_id );
425 if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
426 set_post_format( $post, get_option( 'default_post_format' ) );
429 $post->post_author = '';
430 $post->post_date = '';
431 $post->post_date_gmt = '';
432 $post->post_password = '';
433 $post->post_type = $post_type;
434 $post->post_status = 'draft';
437 $post->comment_status = get_option( 'default_comment_status' );
438 $post->ping_status = get_option( 'default_ping_status' );
439 $post->post_pingback = get_option( 'default_pingback_flag' );
440 $post->post_category = get_option( 'default_category' );
441 $post->page_template = 'default';
442 $post->post_parent = 0;
443 $post->menu_order = 0;
446 $post->post_content = apply_filters( 'default_content', $post_content, $post );
447 $post->post_title = apply_filters( 'default_title', $post_title, $post );
448 $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
449 $post->post_name = '';
455 * Get the default page information to use.
459 * @return object stdClass object containing all the default post data as attributes
461 function get_default_page_to_edit() {
462 $page = get_default_post_to_edit();
463 $page->post_type = 'page';
468 * Get an existing post and format it for editing.
472 * @param unknown_type $id
475 function get_post_to_edit( $id ) {
477 $post = get_post( $id, OBJECT, 'edit' );
479 if ( $post->post_type == 'page' )
480 $post->page_template = get_post_meta( $id, '_wp_page_template', true );
486 * Determine if a post exists based on title, content, and date
490 * @param string $title Post title
491 * @param string $content Optional post content
492 * @param string $date Optional post date
493 * @return int Post ID if post exists, 0 otherwise.
495 function post_exists($title, $content = '', $date = '') {
498 $post_title = stripslashes( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
499 $post_content = stripslashes( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
500 $post_date = stripslashes( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
502 $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
505 if ( !empty ( $date ) ) {
506 $query .= ' AND post_date = %s';
507 $args[] = $post_date;
510 if ( !empty ( $title ) ) {
511 $query .= ' AND post_title = %s';
512 $args[] = $post_title;
515 if ( !empty ( $content ) ) {
516 $query .= 'AND post_content = %s';
517 $args[] = $post_content;
520 if ( !empty ( $args ) )
521 return $wpdb->get_var( $wpdb->prepare($query, $args) );
527 * Creates a new post from the "Write Post" form using $_POST information.
533 function wp_write_post() {
537 if ( isset($_POST['post_type']) )
538 $ptype = get_post_type_object($_POST['post_type']);
540 $ptype = get_post_type_object('post');
542 if ( !current_user_can( $ptype->cap->edit_posts ) ) {
543 if ( 'page' == $ptype->name )
544 return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
546 return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
549 $_POST['post_mime_type'] = '';
551 // Clear out any data in internal vars.
552 unset( $_POST['filter'] );
554 // Check for autosave collisions
555 // Does this need to be updated? ~ Mark
557 if ( isset($_POST['temp_ID']) ) {
558 $temp_id = (int) $_POST['temp_ID'];
559 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
560 $draft_ids = array();
561 foreach ( $draft_ids as $temp => $real )
562 if ( time() + $temp > 86400 ) // 1 day: $temp is equal to -1 * time( then )
563 unset($draft_ids[$temp]);
565 if ( isset($draft_ids[$temp_id]) ) { // Edit, don't write
566 $_POST['post_ID'] = $draft_ids[$temp_id];
567 unset($_POST['temp_ID']);
568 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
573 // Edit don't write if we have a post id.
574 if ( isset( $_POST['ID'] ) ) {
575 $_POST['post_ID'] = $_POST['ID'];
576 unset ( $_POST['ID'] );
578 if ( isset( $_POST['post_ID'] ) ) {
582 $translated = _wp_translate_postdata( false );
583 if ( is_wp_error($translated) )
586 if ( isset($_POST['visibility']) ) {
587 switch ( $_POST['visibility'] ) {
589 $_POST['post_password'] = '';
592 unset( $_POST['sticky'] );
595 $_POST['post_status'] = 'private';
596 $_POST['post_password'] = '';
597 unset( $_POST['sticky'] );
603 $post_ID = wp_insert_post( $_POST );
604 if ( is_wp_error( $post_ID ) )
607 if ( empty($post_ID) )
610 add_meta( $post_ID );
612 add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
614 // Reunite any orphaned attachments with their parent
615 // Does this need to be udpated? ~ Mark
616 if ( !$draft_ids = get_user_option( 'autosave_draft_ids' ) )
617 $draft_ids = array();
618 if ( $draft_temp_id = (int) array_search( $post_ID, $draft_ids ) )
619 _relocate_children( $draft_temp_id, $post_ID );
620 if ( $temp_id && $temp_id != $draft_temp_id )
621 _relocate_children( $temp_id, $post_ID );
623 // Update autosave collision detection
625 $draft_ids[$temp_id] = $post_ID;
626 update_user_option( $user_ID, 'autosave_draft_ids', $draft_ids );
629 // Now that we have an ID we can fix any attachment anchor hrefs
630 _fix_attachment_links( $post_ID );
632 wp_set_post_lock( $post_ID, $GLOBALS['current_user']->ID );
638 * Calls wp_write_post() and handles the errors.
644 function write_post() {
645 $result = wp_write_post();
646 if ( is_wp_error( $result ) )
647 wp_die( $result->get_error_message() );
657 * {@internal Missing Short Description}}
661 * @param unknown_type $post_ID
664 function add_meta( $post_ID ) {
666 $post_ID = (int) $post_ID;
668 $metakeyselect = isset($_POST['metakeyselect']) ? stripslashes( trim( $_POST['metakeyselect'] ) ) : '';
669 $metakeyinput = isset($_POST['metakeyinput']) ? stripslashes( trim( $_POST['metakeyinput'] ) ) : '';
670 $metavalue = isset($_POST['metavalue']) ? maybe_serialize( stripslashes_deep( $_POST['metavalue'] ) ) : '';
671 if ( is_string($metavalue) )
672 $metavalue = trim( $metavalue );
674 if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
675 // We have a key/value pair. If both the select and the
676 // input for the key have data, the input takes precedence:
678 if ('#NONE#' != $metakeyselect)
679 $metakey = $metakeyselect;
682 $metakey = $metakeyinput; // default
684 if ( is_protected_meta( $metakey ) )
687 wp_cache_delete($post_ID, 'post_meta');
688 $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) );
689 $meta_id = $wpdb->insert_id;
690 do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue );
698 * {@internal Missing Short Description}}
702 * @param unknown_type $mid
705 function delete_meta( $mid ) {
709 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
711 do_action( 'delete_postmeta', $mid );
712 wp_cache_delete($post_id, 'post_meta');
713 $rval = $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
714 do_action( 'deleted_postmeta', $mid );
720 * Get a list of previously defined keys.
726 function get_meta_keys() {
729 $keys = $wpdb->get_col( "
733 ORDER BY meta_key" );
739 * {@internal Missing Short Description}}
743 * @param unknown_type $mid
746 function get_post_meta_by_id( $mid ) {
750 $meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->postmeta WHERE meta_id = %d", $mid) );
753 if ( is_serialized_string( $meta->meta_value ) )
754 $meta->meta_value = maybe_unserialize( $meta->meta_value );
759 * {@internal Missing Short Description}}
761 * Some postmeta stuff.
765 * @param unknown_type $postid
768 function has_meta( $postid ) {
771 return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
772 FROM $wpdb->postmeta WHERE post_id = %d
773 ORDER BY meta_key,meta_id", $postid), ARRAY_A );
778 * {@internal Missing Short Description}}
782 * @param unknown_type $meta_id
783 * @param unknown_type $meta_key Expect Slashed
784 * @param unknown_type $meta_value Expect Slashed
787 function update_meta( $meta_id, $meta_key, $meta_value ) {
790 $meta_key = stripslashes($meta_key);
792 if ( is_protected_meta( $meta_key ) )
795 if ( '' === trim( $meta_value ) )
798 $post_id = $wpdb->get_var( $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_id = %d", $meta_id) );
800 $meta_value = maybe_serialize( stripslashes_deep( $meta_value ) );
801 $meta_id = (int) $meta_id;
803 $data = compact( 'meta_key', 'meta_value' );
804 $where = compact( 'meta_id' );
806 do_action( 'update_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
807 $rval = $wpdb->update( $wpdb->postmeta, $data, $where );
808 wp_cache_delete($post_id, 'post_meta');
809 do_action( 'updated_postmeta', $meta_id, $post_id, $meta_key, $meta_value );
819 * Replace hrefs of attachment anchors with up-to-date permalinks.
824 * @param unknown_type $post_ID
827 function _fix_attachment_links( $post_ID ) {
828 global $_fix_attachment_link_id;
830 $post = & get_post( $post_ID, ARRAY_A );
832 $search = "#<a[^>]+rel=('|\")[^'\"]*attachment[^>]*>#ie";
834 // See if we have any rel="attachment" links
835 if ( 0 == preg_match_all( $search, $post['post_content'], $anchor_matches, PREG_PATTERN_ORDER ) )
839 $search = "#[\s]+rel=(\"|')(.*?)wp-att-(\d+)\\1#i";
840 foreach ( $anchor_matches[0] as $anchor ) {
841 if ( 0 == preg_match( $search, $anchor, $id_matches ) )
844 $id = (int) $id_matches[3];
846 // While we have the attachment ID, let's adopt any orphans.
847 $attachment = & get_post( $id, ARRAY_A );
848 if ( ! empty( $attachment) && ! is_object( get_post( $attachment['post_parent'] ) ) ) {
849 $attachment['post_parent'] = $post_ID;
850 // Escape data pulled from DB.
851 $attachment = add_magic_quotes( $attachment );
852 wp_update_post( $attachment );
855 $post_search[$i] = $anchor;
856 $_fix_attachment_link_id = $id;
857 $post_replace[$i] = preg_replace_callback( "#href=(\"|')[^'\"]*\\1#", '_fix_attachment_links_replace_cb', $anchor );
861 $post['post_content'] = str_replace( $post_search, $post_replace, $post['post_content'] );
863 // Escape data pulled from DB.
864 $post = add_magic_quotes( $post);
866 return wp_update_post( $post);
869 function _fix_attachment_links_replace_cb($match) {
870 global $_fix_attachment_link_id;
871 return stripslashes( 'href='.$match[1] ).get_attachment_link( $_fix_attachment_link_id ).stripslashes( $match[1] );
875 * Move child posts to a new parent.
880 * @param unknown_type $old_ID
881 * @param unknown_type $new_ID
884 function _relocate_children( $old_ID, $new_ID ) {
886 $old_ID = (int) $old_ID;
887 $new_ID = (int) $new_ID;
889 $children = $wpdb->get_col( $wpdb->prepare("
892 WHERE meta_key = '_wp_attachment_temp_parent'
893 AND meta_value = %d", $old_ID) );
895 foreach ( $children as $child_id ) {
896 $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
897 delete_post_meta($child_id, '_wp_attachment_temp_parent');
902 * Get all the possible statuses for a post_type
906 * @param string $type The post_type you want the statuses for
907 * @return array As array of all the statuses for the supplied post type
909 function get_available_post_statuses($type = 'post') {
910 $stati = wp_count_posts($type);
912 return array_keys(get_object_vars($stati));
916 * Run the wp query to fetch the posts for listing on the edit posts page
920 * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
923 function wp_edit_posts_query( $q = false ) {
926 $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
927 $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
928 $post_stati = get_post_stati();
930 if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
931 $post_type = $q['post_type'];
935 $avail_post_stati = get_available_post_statuses($post_type);
937 if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
938 $post_status = $q['post_status'];
942 if ( isset($q['orderby']) )
943 $orderby = $q['orderby'];
944 elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
945 $orderby = 'modified';
947 if ( isset($q['order']) )
948 $order = $q['order'];
949 elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
952 $per_page = 'edit_' . $post_type . '_per_page';
953 $posts_per_page = (int) get_user_option( $per_page );
954 if ( empty( $posts_per_page ) || $posts_per_page < 1 )
955 $posts_per_page = 20;
957 $posts_per_page = apply_filters( $per_page, $posts_per_page );
958 $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
960 $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
962 // Hierarchical types require special args.
963 if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
964 $query['orderby'] = 'menu_order title';
965 $query['order'] = 'asc';
966 $query['posts_per_page'] = -1;
967 $query['posts_per_archive_page'] = -1;
970 if ( ! empty( $q['show_sticky'] ) )
971 $query['post__in'] = (array) get_option( 'sticky_posts' );
975 return $avail_post_stati;
979 * Get default post mime types
985 function get_post_mime_types() {
986 $post_mime_types = array( // array( adj, noun )
987 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
988 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
989 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
992 return apply_filters('post_mime_types', $post_mime_types);
996 * {@internal Missing Short Description}}
1000 * @param unknown_type $type
1003 function get_available_post_mime_types($type = 'attachment') {
1006 $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
1011 * {@internal Missing Short Description}}
1015 * @param unknown_type $q
1018 function wp_edit_attachments_query( $q = false ) {
1022 $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
1023 $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
1024 $q['post_type'] = 'attachment';
1025 $post_type = get_post_type_object( 'attachment' );
1026 $states = 'inherit';
1027 if ( current_user_can( $post_type->cap->read_private_posts ) )
1028 $states .= ',private';
1030 $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
1031 $media_per_page = (int) get_user_option( 'upload_per_page' );
1032 if ( empty( $media_per_page ) || $media_per_page < 1 )
1033 $media_per_page = 20;
1034 $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
1036 $post_mime_types = get_post_mime_types();
1037 $avail_post_mime_types = get_available_post_mime_types('attachment');
1039 if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
1040 unset($q['post_mime_type']);
1042 if ( isset($q['detached']) )
1043 add_filter('posts_where', '_edit_attachments_query_helper');
1047 if ( isset($q['detached']) )
1048 remove_filter('posts_where', '_edit_attachments_query_helper');
1050 return array($post_mime_types, $avail_post_mime_types);
1053 function _edit_attachments_query_helper($where) {
1054 return $where .= ' AND post_parent < 1';
1058 * Returns the list of classes to be used by a metabox
1060 * @uses get_user_option()
1063 * @param unknown_type $id
1064 * @param unknown_type $page
1067 function postbox_classes( $id, $page ) {
1068 if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id ) {
1069 $classes = array( '' );
1070 } elseif ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
1071 if ( !is_array( $closed ) ) {
1072 $classes = array( '' );
1074 $classes = in_array( $id, $closed ) ? array( 'closed' ) : array( '' );
1077 $classes = array( '' );
1080 $classes = apply_filters( "postbox_classes_{$page}_{$id}", $classes );
1081 return implode( ' ', $classes );
1085 * {@internal Missing Short Description}}
1089 * @param int|object $id Post ID or post object.
1090 * @param string $title (optional) Title
1091 * @param string $name (optional) Name
1092 * @return array With two entries of type string
1094 function get_sample_permalink($id, $title = null, $name = null) {
1095 $post = &get_post($id);
1097 return array('', '');
1099 $ptype = get_post_type_object($post->post_type);
1101 $original_status = $post->post_status;
1102 $original_date = $post->post_date;
1103 $original_name = $post->post_name;
1105 // Hack: get_permalink would return ugly permalink for
1106 // drafts, so we will fake, that our post is published
1107 if ( in_array($post->post_status, array('draft', 'pending')) ) {
1108 $post->post_status = 'publish';
1109 $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
1112 // If the user wants to set a new name -- override the current one
1113 // Note: if empty name is supplied -- use the title instead, see #6072
1114 if ( !is_null($name) )
1115 $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
1117 $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
1119 $post->filter = 'sample';
1121 $permalink = get_permalink($post, true);
1123 // Replace custom post_type Token with generic pagename token for ease of use.
1124 $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
1126 // Handle page hierarchy
1127 if ( $ptype->hierarchical ) {
1128 $uri = get_page_uri($post);
1129 $uri = untrailingslashit($uri);
1130 $uri = strrev( stristr( strrev( $uri ), '/' ) );
1131 $uri = untrailingslashit($uri);
1132 $uri = apply_filters( 'editable_slug', $uri );
1135 $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
1138 $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
1139 $post->post_status = $original_status;
1140 $post->post_date = $original_date;
1141 $post->post_name = $original_name;
1142 unset($post->filter);
1148 * sample permalink html
1150 * intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1154 * @param int|object $id Post ID or post object.
1155 * @param string $new_title (optional) New title
1156 * @param string $new_slug (optional) New slug
1157 * @return string intended to be used for the inplace editor of the permalink post slug on in the post (and page?) editor.
1159 function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
1161 $post = &get_post($id);
1163 list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
1165 if ( 'publish' == $post->post_status ) {
1166 $ptype = get_post_type_object($post->post_type);
1167 $view_post = $ptype->labels->view_item;
1168 $title = __('Click to edit this part of the permalink');
1170 $title = __('Temporary permalink. Click to edit this part.');
1173 if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
1174 $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink">' . $permalink . "</span>\n";
1175 if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
1176 $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
1177 if ( isset($view_post) )
1178 $return .= "<span id='view-post-btn'><a href='$permalink' class='button' target='_blank'>$view_post</a></span>\n";
1180 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1185 if ( function_exists('mb_strlen') ) {
1186 if ( mb_strlen($post_name) > 30 ) {
1187 $post_name_abridged = mb_substr($post_name, 0, 14). '…' . mb_substr($post_name, -14);
1189 $post_name_abridged = $post_name;
1192 if ( strlen($post_name) > 30 ) {
1193 $post_name_abridged = substr($post_name, 0, 14). '…' . substr($post_name, -14);
1195 $post_name_abridged = $post_name;
1199 $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
1200 $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
1201 $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
1202 $return = '<strong>' . __('Permalink:') . "</strong>\n";
1203 $return .= '<span id="sample-permalink">' . $display_link . "</span>\n";
1204 $return .= '‎'; // Fix bi-directional text display defect in RTL languages.
1205 $return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button hide-if-no-js" onclick="editPermalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
1206 $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
1207 if ( isset($view_post) )
1208 $return .= "<span id='view-post-btn'><a href='$view_link' class='button' target='_blank'>$view_post</a></span>\n";
1210 $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
1216 * Output HTML for the post thumbnail meta-box.
1220 * @param int $thumbnail_id ID of the attachment used for thumbnail
1221 * @return string html
1223 function _wp_post_thumbnail_html( $thumbnail_id = NULL ) {
1224 global $content_width, $_wp_additional_image_sizes, $post_ID;
1225 $set_thumbnail_link = '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set featured image' ) . '" href="' . esc_url( get_upload_iframe_src('image') ) . '" id="set-post-thumbnail" class="thickbox">%s</a></p>';
1226 $content = sprintf($set_thumbnail_link, esc_html__( 'Set featured image' ));
1228 if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
1229 $old_content_width = $content_width;
1230 $content_width = 266;
1231 if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
1232 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
1234 $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
1235 if ( !empty( $thumbnail_html ) ) {
1236 $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" );
1237 $content = sprintf($set_thumbnail_link, $thumbnail_html);
1238 $content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail" onclick="WPRemoveThumbnail(\'' . $ajax_nonce . '\');return false;">' . esc_html__( 'Remove featured image' ) . '</a></p>';
1240 $content_width = $old_content_width;
1243 return apply_filters( 'admin_post_thumbnail_html', $content );
1247 * Check to see if the post is currently being edited by another user.
1251 * @param int $post_id ID of the post to check for editing
1252 * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
1254 function wp_check_post_lock( $post_id ) {
1255 if ( !$post = get_post( $post_id ) )
1258 if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
1261 $lock = explode( ':', $lock );
1263 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1265 $time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
1267 if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
1273 * Mark the post as currently being edited by the current user
1277 * @param int $post_id ID of the post to being edited
1278 * @return bool Returns false if the post doesn't exist of there is no current user
1280 function wp_set_post_lock( $post_id ) {
1281 if ( !$post = get_post( $post_id ) )
1283 if ( 0 == ($user_id = get_current_user_id()) )
1287 $lock = "$now:$user_id";
1289 update_post_meta( $post->ID, '_edit_lock', $lock );
1293 * Outputs the notice message to say that someone else is editing this post at the moment.
1298 function _admin_notice_post_locked() {
1301 $lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
1302 $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
1303 $last_user = get_userdata( $user );
1304 $last_user_name = $last_user ? $last_user->display_name : __('Somebody');
1306 switch ($post->post_type) {
1308 $message = __( 'Warning: %s is currently editing this post' );
1311 $message = __( 'Warning: %s is currently editing this page' );
1314 $message = __( 'Warning: %s is currently editing this.' );
1317 $message = sprintf( $message, esc_html( $last_user_name ) );
1318 echo "<div class='error'><p>$message</p></div>";
1322 * Creates autosave data for the specified post from $_POST data.
1324 * @package WordPress
1325 * @subpackage Post_Revisions
1328 * @uses _wp_translate_postdata()
1329 * @uses _wp_post_revision_fields()
1333 function wp_create_post_autosave( $post_id ) {
1334 $translated = _wp_translate_postdata( true );
1335 if ( is_wp_error( $translated ) )
1338 // Only store one autosave. If there is already an autosave, overwrite it.
1339 if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
1340 $new_autosave = _wp_post_revision_fields( $_POST, true );
1341 $new_autosave['ID'] = $old_autosave->ID;
1342 $new_autosave['post_author'] = get_current_user_id();
1343 return wp_update_post( $new_autosave );
1346 // _wp_put_post_revision() expects unescaped.
1347 $_POST = stripslashes_deep($_POST);
1349 // Otherwise create the new autosave as a special post revision
1350 return _wp_put_post_revision( $_POST, true );
1354 * Save draft or manually autosave for showing preview.
1356 * @package WordPress
1359 * @uses wp_write_post()
1362 * @uses current_user_can()
1363 * @uses wp_create_post_autosave()
1365 * @return str URL to redirect to show the preview
1367 function post_preview() {
1369 $post_ID = (int) $_POST['post_ID'];
1370 $status = get_post_status( $post_ID );
1371 if ( 'auto-draft' == $status )
1372 wp_die( __('Preview not available. Please save as a draft first.') );
1374 if ( isset($_POST['catslist']) )
1375 $_POST['post_category'] = explode(",", $_POST['catslist']);
1377 if ( isset($_POST['tags_input']) )
1378 $_POST['tags_input'] = explode(",", $_POST['tags_input']);
1380 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
1381 unset($_POST['post_category']);
1383 $_POST['ID'] = $post_ID;
1384 $post = get_post($post_ID);
1386 if ( 'page' == $post->post_type ) {
1387 if ( !current_user_can('edit_page', $post_ID) )
1388 wp_die(__('You are not allowed to edit this page.'));
1390 if ( !current_user_can('edit_post', $post_ID) )
1391 wp_die(__('You are not allowed to edit this post.'));
1394 if ( 'draft' == $post->post_status ) {
1396 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
1397 $id = wp_create_post_autosave( $post->ID );
1398 if ( ! is_wp_error($id) )
1402 if ( is_wp_error($id) )
1403 wp_die( $id->get_error_message() );
1405 if ( $_POST['post_status'] == 'draft' ) {
1406 $url = add_query_arg( 'preview', 'true', get_permalink($id) );
1408 $nonce = wp_create_nonce('post_preview_' . $id);
1409 $url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
1416 * Adds the TinyMCE editor used on the Write and Edit screens.
1418 * @package WordPress
1421 * TinyMCE is loaded separately from other Javascript by using wp-tinymce.php. It outputs concatenated
1422 * and optionaly pre-compressed version of the core and all default plugins. Additional plugins are loaded
1423 * directly by TinyMCE using non-blocking method. Custom plugins can be refreshed by adding a query string
1424 * to the URL when queueing them with the mce_external_plugins filter.
1426 * @param bool $teeny optional Output a trimmed down version used in Press This.
1427 * @param mixed $settings optional An array that can add to or overwrite the default TinyMCE settings.
1429 function wp_tiny_mce( $teeny = false, $settings = false ) {
1430 global $concatenate_scripts, $compress_scripts, $tinymce_version, $editor_styles;
1432 if ( ! user_can_richedit() )
1435 $baseurl = includes_url('js/tinymce');
1437 $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
1440 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
1441 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
1442 The + sign marks the default language. More information:
1443 http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker
1445 $mce_spellchecker_languages = apply_filters('mce_spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv');
1448 $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs') );
1451 $plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'wordpress', 'wpfullscreen', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
1454 The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
1455 It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
1456 The url should be absolute and should include the js file name to be loaded. Example:
1457 array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
1458 If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
1460 $mce_external_plugins = apply_filters('mce_external_plugins', array());
1463 if ( ! empty($mce_external_plugins) ) {
1466 The following filter loads external language files for TinyMCE plugins.
1467 It takes an associative array 'plugin_name' => 'path', where path is the
1468 include path to the file. The language file should follow the same format as
1469 /tinymce/langs/wp-langs.php and should define a variable $strings that
1470 holds all translated strings.
1471 When this filter is not used, the function will try to load {mce_locale}.js.
1472 If that is not found, en.js will be tried next.
1474 $mce_external_languages = apply_filters('mce_external_languages', array());
1476 $loaded_langs = array();
1479 if ( ! empty($mce_external_languages) ) {
1480 foreach ( $mce_external_languages as $name => $path ) {
1481 if ( @is_file($path) && @is_readable($path) ) {
1482 include_once($path);
1483 $ext_plugins .= $strings . "\n";
1484 $loaded_langs[] = $name;
1489 foreach ( $mce_external_plugins as $name => $url ) {
1491 if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
1493 $plugins[] = '-' . $name;
1495 $plugurl = dirname($url);
1496 $strings = $str1 = $str2 = '';
1497 if ( ! in_array($name, $loaded_langs) ) {
1498 $path = str_replace( WP_PLUGIN_URL, '', $plugurl );
1499 $path = WP_PLUGIN_DIR . $path . '/langs/';
1501 if ( function_exists('realpath') )
1502 $path = trailingslashit( realpath($path) );
1504 if ( @is_file($path . $mce_locale . '.js') )
1505 $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
1507 if ( @is_file($path . $mce_locale . '_dlg.js') )
1508 $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
1510 if ( 'en' != $mce_locale && empty($strings) ) {
1511 if ( @is_file($path . 'en.js') ) {
1512 $str1 = @file_get_contents($path . 'en.js');
1513 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
1516 if ( @is_file($path . 'en_dlg.js') ) {
1517 $str2 = @file_get_contents($path . 'en_dlg.js');
1518 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
1522 if ( ! empty($strings) )
1523 $ext_plugins .= "\n" . $strings . "\n";
1526 $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
1527 $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
1533 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold, italic, underline, blockquote, separator, strikethrough, bullist, numlist,justifyleft, justifycenter, justifyright, undo, redo, link, unlink, fullscreen') );
1534 $mce_buttons = implode($mce_buttons, ',');
1535 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = '';
1537 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ));
1538 $mce_buttons = implode($mce_buttons, ',');
1540 $mce_buttons_2 = array( 'formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' );
1541 $mce_buttons_2 = apply_filters('mce_buttons_2', $mce_buttons_2);
1542 $mce_buttons_2 = implode($mce_buttons_2, ',');
1544 $mce_buttons_3 = apply_filters('mce_buttons_3', array());
1545 $mce_buttons_3 = implode($mce_buttons_3, ',');
1547 $mce_buttons_4 = apply_filters('mce_buttons_4', array());
1548 $mce_buttons_4 = implode($mce_buttons_4, ',');
1550 $no_captions = (bool) apply_filters( 'disable_captions', '' );
1552 // TinyMCE init settings
1553 $initArray = array (
1554 'mode' => 'specific_textareas',
1555 'editor_selector' => 'theEditor',
1557 'theme' => 'advanced',
1558 'skin' => 'wp_theme',
1559 'theme_advanced_buttons1' => $mce_buttons,
1560 'theme_advanced_buttons2' => $mce_buttons_2,
1561 'theme_advanced_buttons3' => $mce_buttons_3,
1562 'theme_advanced_buttons4' => $mce_buttons_4,
1563 'language' => $mce_locale,
1564 'spellchecker_languages' => $mce_spellchecker_languages,
1565 'theme_advanced_toolbar_location' => 'top',
1566 'theme_advanced_toolbar_align' => 'left',
1567 'theme_advanced_statusbar_location' => 'bottom',
1568 'theme_advanced_resizing' => true,
1569 'theme_advanced_resize_horizontal' => false,
1570 'dialog_type' => 'modal',
1573 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
1574 {selector : 'img,table', classes : 'alignleft'}
1577 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
1578 {selector : 'img,table', classes : 'aligncenter'}
1581 {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
1582 {selector : 'img,table', classes : 'alignright'}
1584 strikethrough : {inline : 'del'}
1586 'relative_urls' => false,
1587 'remove_script_host' => false,
1588 'convert_urls' => false,
1589 'apply_source_formatting' => false,
1590 'remove_linebreaks' => true,
1591 'gecko_spellcheck' => true,
1592 'keep_styles' => false,
1593 'entities' => '38,amp,60,lt,62,gt',
1594 'accessibility_focus' => true,
1595 'tabfocus_elements' => 'major-publishing-actions',
1596 'media_strict' => false,
1597 'paste_remove_styles' => true,
1598 'paste_remove_spans' => true,
1599 'paste_strip_class_attributes' => 'all',
1600 'paste_text_use_dialog' => true,
1601 'extended_valid_elements' => 'article[*],aside[*],audio[*],canvas[*],command[*],datalist[*],details[*],embed[*],figcaption[*],figure[*],footer[*],header[*],hgroup[*],keygen[*],mark[*],meter[*],nav[*],output[*],progress[*],section[*],source[*],summary,time[*],video[*],wbr',
1602 'wpeditimage_disable_captions' => $no_captions,
1603 'wp_fullscreen_content_css' => "$baseurl/plugins/wpfullscreen/css/wp-fullscreen.css",
1604 'plugins' => implode( ',', $plugins ),
1607 if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
1609 $style_uri = get_stylesheet_directory_uri();
1610 if ( ! is_child_theme() ) {
1611 foreach ( $editor_styles as $file )
1612 $mce_css[] = "$style_uri/$file";
1614 $style_dir = get_stylesheet_directory();
1615 $template_uri = get_template_directory_uri();
1616 $template_dir = get_template_directory();
1617 foreach ( $editor_styles as $file ) {
1618 if ( file_exists( "$template_dir/$file" ) )
1619 $mce_css[] = "$template_uri/$file";
1620 if ( file_exists( "$style_dir/$file" ) )
1621 $mce_css[] = "$style_uri/$file";
1624 $mce_css = implode( ',', $mce_css );
1629 $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
1631 if ( ! empty($mce_css) )
1632 $initArray['content_css'] = $mce_css;
1634 if ( is_array($settings) )
1635 $initArray = array_merge($initArray, $settings);
1637 // For people who really REALLY know what they're doing with TinyMCE
1638 // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
1639 // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through "tiny_mce_before_init".
1640 // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
1642 $initArray = apply_filters('teeny_mce_before_init', $initArray);
1644 $initArray = apply_filters('tiny_mce_before_init', $initArray);
1647 if ( empty($initArray['theme_advanced_buttons3']) && !empty($initArray['theme_advanced_buttons4']) ) {
1648 $initArray['theme_advanced_buttons3'] = $initArray['theme_advanced_buttons4'];
1649 $initArray['theme_advanced_buttons4'] = '';
1652 if ( ! isset($concatenate_scripts) )
1653 script_concat_settings();
1655 $language = $initArray['language'];
1657 $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1658 && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
1663 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1664 * These plugins can be refreshed by appending query string to the URL passed to mce_external_plugins filter.
1665 * If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
1667 $version = apply_filters('tiny_mce_version', '');
1668 $version = 'ver=' . $tinymce_version . $version;
1670 if ( 'en' != $language )
1671 include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
1674 foreach ( $initArray as $k => $v ) {
1675 if ( is_bool($v) ) {
1676 $val = $v ? 'true' : 'false';
1677 $mce_options .= $k . ':' . $val . ', ';
1679 } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
1680 $mce_options .= $k . ':' . $v . ', ';
1684 $mce_options .= $k . ':"' . $v . '", ';
1687 $mce_options = rtrim( trim($mce_options), '\n\r,' );
1689 do_action('before_wp_tiny_mce', $initArray); ?>
1691 <script type="text/javascript">
1694 base : "<?php echo $baseurl; ?>",
1696 query : "<?php echo $version; ?>",
1697 mceInit : {<?php echo $mce_options; ?>},
1698 load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1705 echo "<script type='text/javascript' src='$baseurl/wp-tinymce.php?c=1&$version'></script>\n";
1707 echo "<script type='text/javascript' src='$baseurl/tiny_mce.js?$version'></script>\n";
1709 if ( 'en' != $language && isset($lang) )
1710 echo "<script type='text/javascript'>\n$lang\n</script>\n";
1712 echo "<script type='text/javascript' src='$baseurl/langs/wp-langs-en.js?$version'></script>\n";
1715 <script type="text/javascript">
1719 echo "$ext_plugins\n";
1721 if ( ! $compressed ) {
1723 (function(){var t=tinyMCEPreInit,sl=tinymce.ScriptLoader,ln=t.mceInit.language,th=t.mceInit.theme,pl=t.mceInit.plugins;sl.markDone(t.base+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'_dlg.js');tinymce.each(pl.split(','),function(n){if(n&&n.charAt(0)!='-'){sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'.js');sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'_dlg.js');}});})();
1725 tinyMCE.init(tinyMCEPreInit.mceInit);
1730 do_action('after_wp_tiny_mce', $initArray);
1733 // Load additional inline scripts based on active plugins.
1734 function wp_preload_dialogs($init) {
1735 $plugins = preg_split('/[ ,-]+/', $init['plugins']);
1737 if ( in_array( 'wpdialogs', $plugins, true ) ) {
1738 wp_print_scripts('wpdialogs-popup');
1739 wp_print_styles('wp-jquery-ui-dialog');
1742 if ( in_array( 'wplink', $plugins, true ) ) {
1743 require_once ABSPATH . 'wp-admin/includes/internal-linking.php';
1744 ?><div style="display:none;"><?php wp_link_dialog(); ?></div><?php
1745 wp_print_scripts('wplink');
1746 wp_print_styles('wplink');
1749 // Distraction Free Writing mode
1750 if ( in_array( 'wpfullscreen', $plugins, true ) ) {
1751 wp_fullscreen_html();
1752 wp_print_scripts('wp-fullscreen');
1755 wp_print_scripts('word-count');
1758 function wp_quicktags() {
1759 global $tinymce_version;
1761 wp_preload_dialogs( array( 'plugins' => 'wpdialogs,wplink,wpfullscreen' ) );
1763 if ( !user_can_richedit() ) {
1764 wp_enqueue_style( 'tinymce-buttons', includes_url('js/tinymce/themes/advanced/skins/wp_theme/ui.css'), array(), $tinymce_version );
1765 wp_print_styles('tinymce-buttons');
1769 function wp_print_editor_js() {
1770 wp_print_scripts('editor');
1773 function wp_fullscreen_html() {
1774 global $content_width, $post;
1776 $width = isset($content_width) && 800 > $content_width ? $content_width : 800;
1777 $width = $width + 10; // compensate for the padding
1778 $dfw_width = get_user_setting( 'dfw_width', $width );
1779 $save = isset($post->post_status) && $post->post_status == 'publish' ? __('Update') : __('Save');
1781 <div id="wp-fullscreen-body">
1782 <div id="fullscreen-topbar">
1783 <div id="wp-fullscreen-toolbar">
1784 <div id="wp-fullscreen-close"><a href="#" onclick="fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
1785 <div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
1787 <div id="wp-fullscreen-mode-bar"><div id="wp-fullscreen-modes">
1788 <a href="#" onclick="fullscreen.switchmode('tinymce');return false;"><?php _e('Visual'); ?></a>
1789 <a href="#" onclick="fullscreen.switchmode('html');return false;"><?php _e('HTML'); ?></a>
1792 <div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="wp_themeSkin">
1795 $media_link_type = 'image';
1796 if ( is_multisite() && ( ( ! $mu_media_buttons = get_site_option( 'mu_media_buttons' ) ) || empty( $mu_media_buttons['image'] ) ) )
1797 $media_link_type = 'media';
1800 // format: title, onclick, show in both editors
1801 'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'onclick' => 'fullscreen.b();', 'both' => false ),
1802 'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'onclick' => 'fullscreen.i();', 'both' => false ),
1804 'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'onclick' => 'fullscreen.ul();', 'both' => false ),
1805 'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'onclick' => 'fullscreen.ol();', 'both' => false ),
1807 'blockquote' => array( 'title' => __('Blockquote (Alt+Shift+Q)'), 'onclick' => 'fullscreen.blockquote();', 'both' => false ),
1808 'image' => array( 'title' => __('Insert/edit image (Alt + Shift + M)'), 'onclick' => "jQuery('#add_{$media_link_type}').click();", 'both' => true ),
1810 'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'onclick' => 'fullscreen.link();', 'both' => true ),
1811 'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'onclick' => 'fullscreen.unlink();', 'both' => false ),
1813 'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'onclick' => 'fullscreen.help();', 'both' => false )
1816 $buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
1818 foreach ( $buttons as $button => $args ) {
1819 if ( 'separator' == $args ) { ?>
1820 <div><span aria-orientation="vertical" role="separator" class="mceSeparator"></span></div>
1824 <div<?php if ( $args['both'] ) { ?> class="wp-fullscreen-both"<?php } ?>>
1825 <a title="<?php echo $args['title']; ?>" onclick="<?php echo $args['onclick']; ?>return false;" class="mceButton mceButtonEnabled mce_<?php echo $button; ?>" href="#" id="wp_fs_<?php echo $button; ?>" role="button" aria-pressed="false">
1826 <span class="mceIcon mce_<?php echo $button; ?>"></span>
1834 <div id="wp-fullscreen-save">
1835 <span><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
1836 <img src="images/wpspin_light.gif" alt="" />
1837 <input type="button" class="button-primary" value="<?php echo $save; ?>" onclick="fullscreen.save();" />
1844 <div id="wp-fullscreen-wrap" style="width:<?php echo $dfw_width; ?>px;">
1845 <label id="wp-fullscreen-title-prompt-text" for="wp-fullscreen-title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
1846 <input type="text" id="wp-fullscreen-title" value="" autocomplete="off" />
1848 <div id="wp-fullscreen-container">
1849 <textarea id="wp_mce_fullscreen"></textarea>
1852 <div id="wp-fullscreen-status">
1853 <div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
1854 <div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
1859 <div class="fullscreen-overlay" id="fullscreen-overlay"></div>
1860 <div class="fullscreen-overlay fullscreen-fader fade-600" id="fullscreen-fader"></div>