Wordpress/wp-admin/includes/post.php
Ryan Boren a6c8efadb9 Change all core API to expect unslashed rather than slashed arguments.
The exceptions to this are update_post_meta() and add_post_meta() which are often used by plugins in POST handlers and will continue accepting slashed data for now.

Introduce wp_upate_post_meta() and wp_add_post_meta() as unslashed alternatives to update_post_meta() and add_post_meta(). These functions could become methods in WP_Post so don't use them too heavily yet.

Remove all escape() calls from wp_xmlrpc_server. Now that core expects unslashed data this is no longer needed.

Remove addslashes(), addslashes_gpc(), add_magic_quotes() calls on data being prepared for handoff to core functions that until now expected slashed data. Adding slashes in no longer necessary.

Introduce wp_unslash() and use to it remove slashes from GPCS data before using it in core API. Almost every instance of stripslashes() in core should now be wp_unslash(). In the future (a release or three) when GPCS is no longer slashed, wp_unslash() will stop stripping slashes and simply return what is passed. At this point wp_unslash() calls can be removed from core.

Introduce wp_slash() for slashing GPCS data. This will also turn into a noop once GPCS is no longer slashed. wp_slash() should almost never be used. It is mainly of use in unit tests.

Plugins should use wp_unslash() on data being passed to core API.

Plugins should no longer slash data being passed to core. So when you get_post() and then wp_insert_post() the post data from get_post() no longer needs addslashes(). Most plugins were not bothering with this. They will magically start doing the right thing. Unfortunately, those few souls who did it properly will now have to avoid calling addslashes() for 3.6 and newer.

Use wp_kses_post() and wp_kses_data(), which expect unslashed data, instead of wp_filter_post_kses() and wp_filter_kses(), which expect slashed data. Filters are no longer passed slashed data.

Remove many no longer necessary calls to $wpdb->escape() and esc_sql().

In wp_get_referer() and wp_get_original_referer(), return unslashed data.

Remove old stripslashes() calls from WP_Widget::update() handlers. These haven't been necessary since WP_Widget.

Switch several queries over to prepare().

Expect something to break.

Props alexkingorg
see #21767


git-svn-id: https://develop.svn.wordpress.org/trunk@23416 602fd350-edb4-49c9-b593-d223f7449a82
2013-02-14 22:51:06 +00:00

1302 lines
40 KiB
PHP

<?php
/**
* WordPress Post Administration API.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Rename $_POST data from form names to DB post columns.
*
* Manipulates $_POST directly.
*
* @package WordPress
* @since 2.6.0
*
* @param bool $update Are we updating a pre-existing post?
* @param array $post_data Array of post data. Defaults to the contents of $_POST.
* @return object|bool WP_Error on failure, true on success.
*/
function _wp_translate_postdata( $update = false, $post_data = null ) {
if ( empty($post_data) )
$post_data = &$_POST;
if ( $update )
$post_data['ID'] = (int) $post_data['post_ID'];
$ptype = get_post_type_object( $post_data['post_type'] );
if ( $update && ! current_user_can( $ptype->cap->edit_post, $post_data['ID'] ) ) {
if ( 'page' == $post_data['post_type'] )
return new WP_Error( 'edit_others_pages', __( 'You are not allowed to edit pages as this user.' ) );
else
return new WP_Error( 'edit_others_posts', __( 'You are not allowed to edit posts as this user.' ) );
} elseif ( ! $update && ! current_user_can( $ptype->cap->create_posts ) ) {
if ( 'page' == $post_data['post_type'] )
return new WP_Error( 'edit_others_pages', __( 'You are not allowed to create pages as this user.' ) );
else
return new WP_Error( 'edit_others_posts', __( 'You are not allowed to create posts as this user.' ) );
}
if ( isset( $post_data['content'] ) )
$post_data['post_content'] = $post_data['content'];
if ( isset( $post_data['excerpt'] ) )
$post_data['post_excerpt'] = $post_data['excerpt'];
if ( isset( $post_data['parent_id'] ) )
$post_data['post_parent'] = (int) $post_data['parent_id'];
if ( isset($post_data['trackback_url']) )
$post_data['to_ping'] = $post_data['trackback_url'];
if ( !isset($post_data['user_ID']) )
$post_data['user_ID'] = $GLOBALS['user_ID'];
if (!empty ( $post_data['post_author_override'] ) ) {
$post_data['post_author'] = (int) $post_data['post_author_override'];
} else {
if (!empty ( $post_data['post_author'] ) ) {
$post_data['post_author'] = (int) $post_data['post_author'];
} else {
$post_data['post_author'] = (int) $post_data['user_ID'];
}
}
if ( ! $update && isset( $post_data['user_ID'] ) && ( $post_data['post_author'] != $post_data['user_ID'] )
&& ! current_user_can( $ptype->cap->edit_others_posts ) ) {
if ( 'page' == $post_data['post_type'] )
return new WP_Error( 'edit_others_pages', __( 'You are not allowed to create pages as this user.' ) );
else
return new WP_Error( 'edit_others_posts', __( 'You are not allowed to create posts as this user.' ) );
}
// What to do based on which button they pressed
if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
$post_data['post_status'] = 'draft';
if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
$post_data['post_status'] = 'private';
if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
$post_data['post_status'] = 'publish';
if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
$post_data['post_status'] = 'draft';
if ( isset($post_data['pending']) && '' != $post_data['pending'] )
$post_data['post_status'] = 'pending';
if ( isset( $post_data['ID'] ) )
$post_id = $post_data['ID'];
else
$post_id = false;
$previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
// Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
// Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
if ( isset($post_data['post_status']) && ('publish' == $post_data['post_status'] && !current_user_can( $ptype->cap->publish_posts )) )
if ( $previous_status != 'publish' || !current_user_can( 'edit_post', $post_id ) )
$post_data['post_status'] = 'pending';
if ( ! isset($post_data['post_status']) )
$post_data['post_status'] = $previous_status;
if (!isset( $post_data['comment_status'] ))
$post_data['comment_status'] = 'closed';
if (!isset( $post_data['ping_status'] ))
$post_data['ping_status'] = 'closed';
foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
$post_data['edit_date'] = '1';
break;
}
}
if ( !empty( $post_data['edit_date'] ) ) {
$aa = $post_data['aa'];
$mm = $post_data['mm'];
$jj = $post_data['jj'];
$hh = $post_data['hh'];
$mn = $post_data['mn'];
$ss = $post_data['ss'];
$aa = ($aa <= 0 ) ? date('Y') : $aa;
$mm = ($mm <= 0 ) ? date('n') : $mm;
$jj = ($jj > 31 ) ? 31 : $jj;
$jj = ($jj <= 0 ) ? date('j') : $jj;
$hh = ($hh > 23 ) ? $hh -24 : $hh;
$mn = ($mn > 59 ) ? $mn -60 : $mn;
$ss = ($ss > 59 ) ? $ss -60 : $ss;
$post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
$valid_date = wp_checkdate( $mm, $jj, $aa, $post_data['post_date'] );
if ( !$valid_date ) {
return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
}
$post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
}
return $post_data;
}
/**
* Update an existing post with values provided in $_POST.
*
* @since 1.5.0
*
* @param array $post_data Optional.
* @return int Post ID.
*/
function edit_post( $post_data = null ) {
if ( empty( $post_data ) )
$post_data = wp_unslash( $_POST );
// Clear out any data in internal vars.
unset( $post_data['filter'] );
$post_ID = (int) $post_data['post_ID'];
$post = get_post( $post_ID );
$post_data['post_type'] = $post->post_type;
$post_data['post_mime_type'] = $post->post_mime_type;
$ptype = get_post_type_object($post_data['post_type']);
if ( !current_user_can( $ptype->cap->edit_post, $post_ID ) ) {
if ( 'page' == $post_data['post_type'] )
wp_die( __('You are not allowed to edit this page.' ));
else
wp_die( __('You are not allowed to edit this post.' ));
}
$post_data = _wp_translate_postdata( true, $post_data );
if ( is_wp_error($post_data) )
wp_die( $post_data->get_error_message() );
if ( ( empty( $post_data['action'] ) || 'autosave' != $post_data['action'] ) && 'auto-draft' == $post_data['post_status'] ) {
$post_data['post_status'] = 'draft';
}
if ( isset($post_data['visibility']) ) {
switch ( $post_data['visibility'] ) {
case 'public' :
$post_data['post_password'] = '';
break;
case 'password' :
unset( $post_data['sticky'] );
break;
case 'private' :
$post_data['post_status'] = 'private';
$post_data['post_password'] = '';
unset( $post_data['sticky'] );
break;
}
}
// Post Formats
if ( isset( $post_data['post_format'] ) ) {
if ( current_theme_supports( 'post-formats', $post_data['post_format'] ) )
set_post_format( $post_ID, $post_data['post_format'] );
elseif ( '0' == $post_data['post_format'] )
set_post_format( $post_ID, false );
}
// Meta Stuff
if ( isset($post_data['meta']) && $post_data['meta'] ) {
foreach ( $post_data['meta'] as $key => $value ) {
if ( !$meta = get_post_meta_by_id( $key ) )
continue;
if ( $meta->post_id != $post_ID )
continue;
if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) )
continue;
update_meta( $key, $value['key'], $value['value'] );
}
}
if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
foreach ( $post_data['deletemeta'] as $key => $value ) {
if ( !$meta = get_post_meta_by_id( $key ) )
continue;
if ( $meta->post_id != $post_ID )
continue;
if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) )
continue;
delete_meta( $key );
}
}
// Attachment stuff
if ( 'attachment' == $post_data['post_type'] ) {
if ( isset( $post_data[ '_wp_attachment_image_alt' ] ) ) {
$image_alt = get_post_meta( $post_ID, '_wp_attachment_image_alt', true );
if ( $image_alt != $post_data['_wp_attachment_image_alt'] ) {
$image_alt = wp_strip_all_tags( $post_data['_wp_attachment_image_alt'], true );
wp_update_post_meta( $post_ID, '_wp_attachment_image_alt', $image_alt );
}
}
$attachment_data = isset( $post_data['attachments'][ $post_ID ] ) ? $post_data['attachments'][ $post_ID ] : array();
$post_data = apply_filters( 'attachment_fields_to_save', $post_data, $attachment_data );
}
add_meta( $post_ID );
wp_update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
wp_update_post( $post_data );
// Now that we have an ID we can fix any attachment anchor hrefs
_fix_attachment_links( $post_ID );
wp_set_post_lock( $post_ID );
if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
if ( ! empty( $post_data['sticky'] ) )
stick_post( $post_ID );
else
unstick_post( $post_ID );
}
return $post_ID;
}
/**
* Process the post data for the bulk editing of posts.
*
* Updates all bulk edited posts/pages, adding (but not removing) tags and
* categories. Skips pages when they would be their own parent or child.
*
* @since 2.7.0
*
* @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
* @return array
*/
function bulk_edit_posts( $post_data = null ) {
global $wpdb;
if ( empty($post_data) )
$post_data = &$_POST;
if ( isset($post_data['post_type']) )
$ptype = get_post_type_object($post_data['post_type']);
else
$ptype = get_post_type_object('post');
if ( !current_user_can( $ptype->cap->edit_posts ) ) {
if ( 'page' == $ptype->name )
wp_die( __('You are not allowed to edit pages.'));
else
wp_die( __('You are not allowed to edit posts.'));
}
if ( -1 == $post_data['_status'] ) {
$post_data['post_status'] = null;
unset($post_data['post_status']);
} else {
$post_data['post_status'] = $post_data['_status'];
}
unset($post_data['_status']);
$post_IDs = array_map( 'intval', (array) $post_data['post'] );
$reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
foreach ( $reset as $field ) {
if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
unset($post_data[$field]);
}
if ( isset($post_data['post_category']) ) {
if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
$new_cats = array_map( 'absint', $post_data['post_category'] );
else
unset($post_data['post_category']);
}
$tax_input = array();
if ( isset($post_data['tax_input'])) {
foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
if ( empty($terms) )
continue;
if ( is_taxonomy_hierarchical( $tax_name ) ) {
$tax_input[ $tax_name ] = array_map( 'absint', $terms );
} else {
$comma = _x( ',', 'tag delimiter' );
if ( ',' !== $comma )
$terms = str_replace( $comma, ',', $terms );
$tax_input[ $tax_name ] = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
}
}
}
if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
$pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
$children = array();
for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
$children[] = $parent;
foreach ( $pages as $page ) {
if ( $page->ID == $parent ) {
$parent = $page->post_parent;
break;
}
}
}
}
if ( isset( $post_data['post_format'] ) ) {
if ( '0' == $post_data['post_format'] )
$post_data['post_format'] = false;
// don't change the post format if it's not supported or not '0' (standard)
elseif ( ! current_theme_supports( 'post-formats', $post_data['post_format'] ) )
unset( $post_data['post_format'] );
}
$updated = $skipped = $locked = array();
foreach ( $post_IDs as $post_ID ) {
$post_type_object = get_post_type_object( get_post_type( $post_ID ) );
if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
$skipped[] = $post_ID;
continue;
}
if ( wp_check_post_lock( $post_ID ) ) {
$locked[] = $post_ID;
continue;
}
$post = get_post( $post_ID );
$tax_names = get_object_taxonomies( $post );
foreach ( $tax_names as $tax_name ) {
$taxonomy_obj = get_taxonomy($tax_name);
if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
$new_terms = $tax_input[$tax_name];
else
$new_terms = array();
if ( $taxonomy_obj->hierarchical )
$current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
else
$current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
$post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
}
if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
$cats = (array) wp_get_post_categories($post_ID);
$post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
unset( $post_data['tax_input']['category'] );
}
$post_data['post_mime_type'] = $post->post_mime_type;
$post_data['guid'] = $post->guid;
$post_data['ID'] = $post_ID;
$updated[] = wp_update_post( $post_data );
if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
if ( 'sticky' == $post_data['sticky'] )
stick_post( $post_ID );
else
unstick_post( $post_ID );
}
if ( isset( $post_data['post_format'] ) )
set_post_format( $post_ID, $post_data['post_format'] );
}
return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
}
/**
* Default post information to use when populating the "Write Post" form.
*
* @since 2.0.0
*
* @param string $post_type A post type string, defaults to 'post'.
* @return WP_Post Post object containing all the default post data as attributes
*/
function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
global $wpdb;
$post_title = '';
if ( !empty( $_REQUEST['post_title'] ) )
$post_title = esc_html( wp_unslash( $_REQUEST['post_title'] ));
$post_content = '';
if ( !empty( $_REQUEST['content'] ) )
$post_content = esc_html( wp_unslash( $_REQUEST['content'] ));
$post_excerpt = '';
if ( !empty( $_REQUEST['excerpt'] ) )
$post_excerpt = esc_html( wp_unslash( $_REQUEST['excerpt'] ));
if ( $create_in_db ) {
$post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
$post = get_post( $post_id );
if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
set_post_format( $post, get_option( 'default_post_format' ) );
} else {
$post = new stdClass;
$post->ID = 0;
$post->post_author = '';
$post->post_date = '';
$post->post_date_gmt = '';
$post->post_password = '';
$post->post_type = $post_type;
$post->post_status = 'draft';
$post->to_ping = '';
$post->pinged = '';
$post->comment_status = get_option( 'default_comment_status' );
$post->ping_status = get_option( 'default_ping_status' );
$post->post_pingback = get_option( 'default_pingback_flag' );
$post->post_category = get_option( 'default_category' );
$post->page_template = 'default';
$post->post_parent = 0;
$post->menu_order = 0;
$post = new WP_Post( $post );
}
$post->post_content = apply_filters( 'default_content', $post_content, $post );
$post->post_title = apply_filters( 'default_title', $post_title, $post );
$post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
$post->post_name = '';
return $post;
}
/**
* Determine if a post exists based on title, content, and date
*
* @since 2.0.0
*
* @param string $title Post title
* @param string $content Optional post content
* @param string $date Optional post date
* @return int Post ID if post exists, 0 otherwise.
*/
function post_exists($title, $content = '', $date = '') {
global $wpdb;
$post_title = sanitize_post_field( 'post_title', $title, 0, 'db' );
$post_content = sanitize_post_field( 'post_content', $content, 0, 'db' );
$post_date = sanitize_post_field( 'post_date', $date, 0, 'db' );
$query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
$args = array();
if ( !empty ( $date ) ) {
$query .= ' AND post_date = %s';
$args[] = $post_date;
}
if ( !empty ( $title ) ) {
$query .= ' AND post_title = %s';
$args[] = $post_title;
}
if ( !empty ( $content ) ) {
$query .= 'AND post_content = %s';
$args[] = $post_content;
}
if ( !empty ( $args ) )
return (int) $wpdb->get_var( $wpdb->prepare($query, $args) );
return 0;
}
/**
* Creates a new post from the "Write Post" form using $_POST information.
*
* @since 2.1.0
*
* @return unknown
*/
function wp_write_post() {
global $user_ID;
if ( isset($_POST['post_type']) )
$ptype = get_post_type_object($_POST['post_type']);
else
$ptype = get_post_type_object('post');
if ( !current_user_can( $ptype->cap->edit_posts ) ) {
if ( 'page' == $ptype->name )
return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
else
return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
}
$_POST['post_mime_type'] = '';
// Clear out any data in internal vars.
unset( $_POST['filter'] );
// Edit don't write if we have a post id.
if ( isset( $_POST['post_ID'] ) )
return edit_post();
$translated = _wp_translate_postdata( false );
if ( is_wp_error($translated) )
return $translated;
if ( isset($_POST['visibility']) ) {
switch ( $_POST['visibility'] ) {
case 'public' :
$_POST['post_password'] = '';
break;
case 'password' :
unset( $_POST['sticky'] );
break;
case 'private' :
$_POST['post_status'] = 'private';
$_POST['post_password'] = '';
unset( $_POST['sticky'] );
break;
}
}
// Create the post.
$post_ID = wp_insert_post( wp_unslash( $_POST ) );
if ( is_wp_error( $post_ID ) )
return $post_ID;
if ( empty($post_ID) )
return 0;
add_meta( $post_ID );
wp_add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
// Now that we have an ID we can fix any attachment anchor hrefs
_fix_attachment_links( $post_ID );
wp_set_post_lock( $post_ID );
return $post_ID;
}
/**
* Calls wp_write_post() and handles the errors.
*
* @since 2.0.0
* @uses wp_write_post()
* @uses is_wp_error()
* @uses wp_die()
* @return unknown
*/
function write_post() {
$result = wp_write_post();
if ( is_wp_error( $result ) )
wp_die( $result->get_error_message() );
else
return $result;
}
//
// Post Meta
//
/**
* {@internal Missing Short Description}}
*
* @since 1.2.0
*
* @param unknown_type $post_ID
* @return unknown
*/
function add_meta( $post_ID ) {
global $wpdb;
$post_ID = (int) $post_ID;
$metakeyselect = isset($_POST['metakeyselect']) ? wp_unslash( trim( $_POST['metakeyselect'] ) ) : '';
$metakeyinput = isset($_POST['metakeyinput']) ? wp_unslash( trim( $_POST['metakeyinput'] ) ) : '';
$metavalue = isset($_POST['metavalue']) ? wp_unslash( trim( $_POST['metavalue'] ) ) : '';
if ( is_string( $metavalue ) )
$metavalue = trim( $metavalue );
if ( ('0' === $metavalue || ! empty ( $metavalue ) ) && ( ( ( '#NONE#' != $metakeyselect ) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput ) ) ) {
// We have a key/value pair. If both the select and the
// input for the key have data, the input takes precedence:
if ( '#NONE#' != $metakeyselect )
$metakey = $metakeyselect;
if ( $metakeyinput )
$metakey = $metakeyinput; // default
if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) )
return false;
return wp_add_post_meta( $post_ID, $metakey, $metavalue );
}
return false;
} // add_meta
/**
* {@internal Missing Short Description}}
*
* @since 1.2.0
*
* @param unknown_type $mid
* @return unknown
*/
function delete_meta( $mid ) {
return delete_metadata_by_mid( 'post' , $mid );
}
/**
* Get a list of previously defined keys.
*
* @since 1.2.0
*
* @return unknown
*/
function get_meta_keys() {
global $wpdb;
$keys = $wpdb->get_col( "
SELECT meta_key
FROM $wpdb->postmeta
GROUP BY meta_key
ORDER BY meta_key" );
return $keys;
}
/**
* {@internal Missing Short Description}}
*
* @since 2.1.0
*
* @param unknown_type $mid
* @return unknown
*/
function get_post_meta_by_id( $mid ) {
return get_metadata_by_mid( 'post', $mid );
}
/**
* {@internal Missing Short Description}}
*
* Some postmeta stuff.
*
* @since 1.2.0
*
* @param unknown_type $postid
* @return unknown
*/
function has_meta( $postid ) {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
FROM $wpdb->postmeta WHERE post_id = %d
ORDER BY meta_key,meta_id", $postid), ARRAY_A );
}
/**
* {@internal Missing Short Description}}
*
* @since 1.2.0
*
* @param unknown_type $meta_id
* @param unknown_type $meta_key
* @param unknown_type $meta_value
* @return unknown
*/
function update_meta( $meta_id, $meta_key, $meta_value ) {
return update_metadata_by_mid( 'post', $meta_id, $meta_value, $meta_key );
}
//
// Private
//
/**
* Replace hrefs of attachment anchors with up-to-date permalinks.
*
* @since 2.3.0
* @access private
*
* @param unknown_type $post_ID
* @return unknown
*/
function _fix_attachment_links( $post_ID ) {
$post = get_post( $post_ID, ARRAY_A );
$content = $post['post_content'];
// quick sanity check, don't run if no pretty permalinks or post is not published
if ( !get_option('permalink_structure') || $post['post_status'] != 'publish' )
return;
// Short if there aren't any links or no '?attachment_id=' strings (strpos cannot be zero)
if ( !strpos($content, '?attachment_id=') || !preg_match_all( '/<a ([^>]+)>[\s\S]+?<\/a>/', $content, $link_matches ) )
return;
$site_url = get_bloginfo('url');
$site_url = substr( $site_url, (int) strpos($site_url, '://') ); // remove the http(s)
$replace = '';
foreach ( $link_matches[1] as $key => $value ) {
if ( !strpos($value, '?attachment_id=') || !strpos($value, 'wp-att-')
|| !preg_match( '/href=(["\'])[^"\']*\?attachment_id=(\d+)[^"\']*\\1/', $value, $url_match )
|| !preg_match( '/rel=["\'][^"\']*wp-att-(\d+)/', $value, $rel_match ) )
continue;
$quote = $url_match[1]; // the quote (single or double)
$url_id = (int) $url_match[2];
$rel_id = (int) $rel_match[1];
if ( !$url_id || !$rel_id || $url_id != $rel_id || strpos($url_match[0], $site_url) === false )
continue;
$link = $link_matches[0][$key];
$replace = str_replace( $url_match[0], 'href=' . $quote . get_attachment_link( $url_id ) . $quote, $link );
$content = str_replace( $link, $replace, $content );
}
if ( $replace ) {
$post['post_content'] = $content;
return wp_update_post($post);
}
}
/**
* Move child posts to a new parent.
*
* @since 2.3.0
* @access private
*
* @param unknown_type $old_ID
* @param unknown_type $new_ID
* @return unknown
*/
function _relocate_children( $old_ID, $new_ID ) {
global $wpdb;
$old_ID = (int) $old_ID;
$new_ID = (int) $new_ID;
$children = $wpdb->get_col( $wpdb->prepare("
SELECT post_id
FROM $wpdb->postmeta
WHERE meta_key = '_wp_attachment_temp_parent'
AND meta_value = %d", $old_ID) );
foreach ( $children as $child_id ) {
$wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
delete_post_meta($child_id, '_wp_attachment_temp_parent');
}
}
/**
* Get all the possible statuses for a post_type
*
* @since 2.5.0
*
* @param string $type The post_type you want the statuses for
* @return array As array of all the statuses for the supplied post type
*/
function get_available_post_statuses($type = 'post') {
$stati = wp_count_posts($type);
return array_keys(get_object_vars($stati));
}
/**
* Run the wp query to fetch the posts for listing on the edit posts page
*
* @since 2.5.0
*
* @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
* @return array
*/
function wp_edit_posts_query( $q = false ) {
if ( false === $q )
$q = $_GET;
$q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
$q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
$post_stati = get_post_stati();
if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
$post_type = $q['post_type'];
else
$post_type = 'post';
$avail_post_stati = get_available_post_statuses($post_type);
if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
$post_status = $q['post_status'];
$perm = 'readable';
}
if ( isset($q['orderby']) )
$orderby = $q['orderby'];
elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
$orderby = 'modified';
if ( isset($q['order']) )
$order = $q['order'];
elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
$order = 'ASC';
$per_page = 'edit_' . $post_type . '_per_page';
$posts_per_page = (int) get_user_option( $per_page );
if ( empty( $posts_per_page ) || $posts_per_page < 1 )
$posts_per_page = 20;
$posts_per_page = apply_filters( $per_page, $posts_per_page );
$posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
$query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
// Hierarchical types require special args.
if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
$query['orderby'] = 'menu_order title';
$query['order'] = 'asc';
$query['posts_per_page'] = -1;
$query['posts_per_archive_page'] = -1;
}
if ( ! empty( $q['show_sticky'] ) )
$query['post__in'] = (array) get_option( 'sticky_posts' );
wp( $query );
return $avail_post_stati;
}
/**
* {@internal Missing Short Description}}
*
* @since 2.5.0
*
* @param unknown_type $type
* @return unknown
*/
function get_available_post_mime_types($type = 'attachment') {
global $wpdb;
$types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
return $types;
}
/**
* Executes a query for attachments. An array of WP_Query arguments
* can be passed in, which will override the arguments set by this function.
*
* @since 2.5.0
* @uses apply_filters() Calls 'upload_per_page' on posts_per_page argument
*
* @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
* @return array
*/
function wp_edit_attachments_query( $q = false ) {
if ( false === $q )
$q = $_GET;
$q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
$q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
$q['post_type'] = 'attachment';
$post_type = get_post_type_object( 'attachment' );
$states = 'inherit';
if ( current_user_can( $post_type->cap->read_private_posts ) )
$states .= ',private';
$q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
$media_per_page = (int) get_user_option( 'upload_per_page' );
if ( empty( $media_per_page ) || $media_per_page < 1 )
$media_per_page = 20;
$q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
$post_mime_types = get_post_mime_types();
$avail_post_mime_types = get_available_post_mime_types('attachment');
if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
unset($q['post_mime_type']);
if ( isset($q['detached']) )
add_filter('posts_where', '_edit_attachments_query_helper');
wp( $q );
if ( isset($q['detached']) )
remove_filter('posts_where', '_edit_attachments_query_helper');
return array($post_mime_types, $avail_post_mime_types);
}
function _edit_attachments_query_helper($where) {
global $wpdb;
return $where .= " AND {$wpdb->posts}.post_parent < 1";
}
/**
* Returns the list of classes to be used by a metabox
*
* @uses get_user_option()
* @since 2.5.0
*
* @param unknown_type $id
* @param unknown_type $page
* @return unknown
*/
function postbox_classes( $id, $page ) {
if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id ) {
$classes = array( '' );
} elseif ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
if ( !is_array( $closed ) ) {
$classes = array( '' );
} else {
$classes = in_array( $id, $closed ) ? array( 'closed' ) : array( '' );
}
} else {
$classes = array( '' );
}
$classes = apply_filters( "postbox_classes_{$page}_{$id}", $classes );
return implode( ' ', $classes );
}
/**
* {@internal Missing Short Description}}
*
* @since 2.5.0
*
* @param int|object $id Post ID or post object.
* @param string $title (optional) Title
* @param string $name (optional) Name
* @return array With two entries of type string
*/
function get_sample_permalink($id, $title = null, $name = null) {
$post = get_post($id);
if ( !$post->ID )
return array('', '');
$ptype = get_post_type_object($post->post_type);
$original_status = $post->post_status;
$original_date = $post->post_date;
$original_name = $post->post_name;
// Hack: get_permalink would return ugly permalink for
// drafts, so we will fake, that our post is published
if ( in_array($post->post_status, array('draft', 'pending')) ) {
$post->post_status = 'publish';
$post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
}
// If the user wants to set a new name -- override the current one
// Note: if empty name is supplied -- use the title instead, see #6072
if ( !is_null($name) )
$post->post_name = sanitize_title($name ? $name : $title, $post->ID);
$post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
$post->filter = 'sample';
$permalink = get_permalink($post, true);
// Replace custom post_type Token with generic pagename token for ease of use.
$permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
// Handle page hierarchy
if ( $ptype->hierarchical ) {
$uri = get_page_uri($post);
$uri = untrailingslashit($uri);
$uri = strrev( stristr( strrev( $uri ), '/' ) );
$uri = untrailingslashit($uri);
$uri = apply_filters( 'editable_slug', $uri );
if ( !empty($uri) )
$uri .= '/';
$permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
}
$permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
$post->post_status = $original_status;
$post->post_date = $original_date;
$post->post_name = $original_name;
unset($post->filter);
return $permalink;
}
/**
* Returns the HTML of the sample permalink slug editor.
*
* @since 2.5.0
*
* @param int|object $id Post ID or post object.
* @param string $new_title Optional. New title.
* @param string $new_slug Optional. New slug.
* @return string The HTML of the sample permalink slug editor.
*/
function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
global $wpdb;
$post = get_post($id);
list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
if ( 'publish' == get_post_status( $post ) ) {
$ptype = get_post_type_object($post->post_type);
$view_post = $ptype->labels->view_item;
$title = __('Click to edit this part of the permalink');
} else {
$title = __('Temporary permalink. Click to edit this part.');
}
if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
$return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink" tabindex="-1">' . $permalink . "</span>\n";
if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
$return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button button-small" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
if ( isset( $view_post ) )
$return .= "<span id='view-post-btn'><a href='$permalink' class='button button-small'>$view_post</a></span>\n";
$return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
return $return;
}
if ( function_exists('mb_strlen') ) {
if ( mb_strlen($post_name) > 30 ) {
$post_name_abridged = mb_substr($post_name, 0, 14). '&hellip;' . mb_substr($post_name, -14);
} else {
$post_name_abridged = $post_name;
}
} else {
if ( strlen($post_name) > 30 ) {
$post_name_abridged = substr($post_name, 0, 14). '&hellip;' . substr($post_name, -14);
} else {
$post_name_abridged = $post_name;
}
}
$post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
$display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
$view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
$return = '<strong>' . __('Permalink:') . "</strong>\n";
$return .= '<span id="sample-permalink" tabindex="-1">' . $display_link . "</span>\n";
$return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
$return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button button-small hide-if-no-js" onclick="editPermalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
$return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
if ( isset($view_post) )
$return .= "<span id='view-post-btn'><a href='$view_link' class='button button-small'>$view_post</a></span>\n";
$return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
return $return;
}
/**
* Output HTML for the post thumbnail meta-box.
*
* @since 2.9.0
*
* @param int $thumbnail_id ID of the attachment used for thumbnail
* @param mixed $post The post ID or object associated with the thumbnail, defaults to global $post.
* @return string html
*/
function _wp_post_thumbnail_html( $thumbnail_id = null, $post = null ) {
global $content_width, $_wp_additional_image_sizes;
$post = get_post( $post );
$upload_iframe_src = esc_url( get_upload_iframe_src('image', $post->ID ) );
$set_thumbnail_link = '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set featured image' ) . '" href="%s" id="set-post-thumbnail" class="thickbox">%s</a></p>';
$content = sprintf( $set_thumbnail_link, $upload_iframe_src, esc_html__( 'Set featured image' ) );
if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
$old_content_width = $content_width;
$content_width = 266;
if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
$thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
else
$thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
if ( !empty( $thumbnail_html ) ) {
$ajax_nonce = wp_create_nonce( 'set_post_thumbnail-' . $post->ID );
$content = sprintf( $set_thumbnail_link, $upload_iframe_src, $thumbnail_html );
$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>';
}
$content_width = $old_content_width;
}
return apply_filters( 'admin_post_thumbnail_html', $content, $post->ID );
}
/**
* Check to see if the post is currently being edited by another user.
*
* @since 2.5.0
*
* @param int $post_id ID of the post to check for editing
* @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
*/
function wp_check_post_lock( $post_id ) {
if ( !$post = get_post( $post_id ) )
return false;
if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
return false;
$lock = explode( ':', $lock );
$time = $lock[0];
$user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
$time_window = apply_filters( 'wp_check_post_lock_window', AUTOSAVE_INTERVAL * 2 );
if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
return $user;
return false;
}
/**
* Mark the post as currently being edited by the current user
*
* @since 2.5.0
*
* @param int $post_id ID of the post to being edited
* @return bool|array Returns false if the post doesn't exist of there is no current user, or
* an array of the lock time and the user ID.
*/
function wp_set_post_lock( $post_id ) {
if ( !$post = get_post( $post_id ) )
return false;
if ( 0 == ($user_id = get_current_user_id()) )
return false;
$now = time();
$lock = "$now:$user_id";
wp_update_post_meta( $post->ID, '_edit_lock', $lock );
return array( $now, $user_id );
}
/**
* Outputs the notice message to say that someone else is editing this post at the moment.
*
* @since 2.8.5
* @return none
*/
function _admin_notice_post_locked() {
$post = get_post();
$lock = explode( ':', get_post_meta( $post->ID, '_edit_lock', true ) );
$user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
$last_user = get_userdata( $user );
$last_user_name = $last_user ? $last_user->display_name : __('Somebody');
switch ($post->post_type) {
case 'post':
$message = __( 'Warning: %s is currently editing this post' );
break;
case 'page':
$message = __( 'Warning: %s is currently editing this page' );
break;
default:
$message = __( 'Warning: %s is currently editing this.' );
}
$message = sprintf( $message, esc_html( $last_user_name ) );
echo "<div class='error'><p>$message</p></div>";
}
/**
* Creates autosave data for the specified post from $_POST data.
*
* @package WordPress
* @subpackage Post_Revisions
* @since 2.6.0
*
* @uses _wp_translate_postdata()
* @uses _wp_post_revision_fields()
*
* @return unknown
*/
function wp_create_post_autosave( $post_id ) {
$translated = _wp_translate_postdata( true );
if ( is_wp_error( $translated ) )
return $translated;
// Only store one autosave. If there is already an autosave, overwrite it.
if ( $old_autosave = wp_get_post_autosave( $post_id ) ) {
$new_autosave = _wp_post_revision_fields( wp_unslash( $_POST ), true );
$new_autosave['ID'] = $old_autosave->ID;
$new_autosave['post_author'] = get_current_user_id();
return wp_update_post( $new_autosave );
}
// _wp_put_post_revision() expects unescaped.
$_POST = wp_unslash( $_POST );
// Otherwise create the new autosave as a special post revision
return _wp_put_post_revision( $_POST, true );
}
/**
* Save draft or manually autosave for showing preview.
*
* @package WordPress
* @since 2.7.0
*
* @uses get_post_status()
* @uses edit_post()
* @uses get_post()
* @uses current_user_can()
* @uses wp_die()
* @uses wp_create_post_autosave()
* @uses add_query_arg()
* @uses wp_create_nonce()
*
* @return str URL to redirect to show the preview
*/
function post_preview() {
$post_ID = (int) $_POST['post_ID'];
$status = get_post_status( $post_ID );
if ( 'auto-draft' == $status )
wp_die( __('Preview not available. Please save as a draft first.') );
if ( isset($_POST['catslist']) )
$_POST['post_category'] = explode(",", $_POST['catslist']);
if ( isset($_POST['tags_input']) )
$_POST['tags_input'] = explode(",", $_POST['tags_input']);
if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
unset($_POST['post_category']);
$_POST['ID'] = $post_ID;
$post = get_post($post_ID);
if ( 'page' == $post->post_type ) {
if ( !current_user_can('edit_page', $post_ID) )
wp_die(__('You are not allowed to edit this page.'));
} else {
if ( !current_user_can('edit_post', $post_ID) )
wp_die(__('You are not allowed to edit this post.'));
}
if ( 'draft' == $post->post_status ) {
$id = edit_post();
} else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
$id = wp_create_post_autosave( $post->ID );
if ( ! is_wp_error($id) )
$id = $post->ID;
}
if ( is_wp_error($id) )
wp_die( $id->get_error_message() );
if ( $_POST['post_status'] == 'draft' ) {
$url = add_query_arg( 'preview', 'true', get_permalink($id) );
} else {
$nonce = wp_create_nonce('post_preview_' . $id);
$url = add_query_arg( array( 'preview' => 'true', 'preview_id' => $id, 'preview_nonce' => $nonce ), get_permalink($id) );
}
return $url;
}