Simplify the include graph after work to split out classes.

see #33413. More details there.

Built from https://develop.svn.wordpress.org/trunk@35718


git-svn-id: http://core.svn.wordpress.org/trunk@35682 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrew Nacin 2015-11-20 07:24:30 +00:00
parent e549e56f02
commit 1579e45d41
31 changed files with 22844 additions and 23022 deletions

View File

@ -58,6 +58,8 @@ require_once(ABSPATH . 'wp-admin/includes/taxonomy.php');
/** WordPress Template Administration API */
require_once(ABSPATH . 'wp-admin/includes/template.php');
require_once(ABSPATH . 'wp-admin/includes/class-walker-category-checklist.php');
require_once(ABSPATH . 'wp-admin/includes/class-wp-internal-pointers.php');
/** WordPress List Table Administration API and base class */
require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ $_old_files = array(
'wp-admin/link-categories.php',
'wp-admin/list-manipulation.js',
'wp-admin/list-manipulation.php',
'wp-includes/comment-functions.php',
'wp-includes/feed-functions.php',
'wp-includes/functions-compat.php',
'wp-includes/functions-formatting.php',

View File

@ -1,612 +0,0 @@
<?php
/**
* User API: Top-level role and capabilities functionality
*
* @package WordPress
* @subpackage Users
* @since 4.4.0
*/
/**
* Map meta capabilities to primitive capabilities.
*
* This does not actually compare whether the user ID has the actual capability,
* just what the capability or capabilities are. Meta capability list value can
* be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
* 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
*
* @since 2.0.0
*
* @param string $cap Capability name.
* @param int $user_id User ID.
* @param int $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
* "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
* by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
* 'edit_others_posts', etc. The parameter is accessed via func_get_args().
* @return array Actual capabilities for meta capability.
*/
function map_meta_cap( $cap, $user_id ) {
$args = array_slice( func_get_args(), 2 );
$caps = array();
switch ( $cap ) {
case 'remove_user':
$caps[] = 'remove_users';
break;
case 'promote_user':
case 'add_users':
$caps[] = 'promote_users';
break;
case 'edit_user':
case 'edit_users':
// Allow user to edit itself
if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] )
break;
// In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
$caps[] = 'do_not_allow';
} else {
$caps[] = 'edit_users'; // edit_user maps to edit_users.
}
break;
case 'delete_post':
case 'delete_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'delete_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
// If the post author is set and the user is the author...
if ( $post->post_author && $user_id == $post->post_author ) {
// If the post is published...
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->delete_published_posts;
} elseif ( 'trash' == $post->post_status ) {
if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
$caps[] = $post_type->cap->delete_published_posts;
}
} else {
// If the post is draft...
$caps[] = $post_type->cap->delete_posts;
}
} else {
// The user is trying to edit someone else's post.
$caps[] = $post_type->cap->delete_others_posts;
// The post is published, extra cap required.
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->delete_published_posts;
} elseif ( 'private' == $post->post_status ) {
$caps[] = $post_type->cap->delete_private_posts;
}
}
break;
// edit_post breaks down to edit_posts, edit_published_posts, or
// edit_others_posts
case 'edit_post':
case 'edit_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'edit_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
// If the post author is set and the user is the author...
if ( $post->post_author && $user_id == $post->post_author ) {
// If the post is published...
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->edit_published_posts;
} elseif ( 'trash' == $post->post_status ) {
if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
$caps[] = $post_type->cap->edit_published_posts;
}
} else {
// If the post is draft...
$caps[] = $post_type->cap->edit_posts;
}
} else {
// The user is trying to edit someone else's post.
$caps[] = $post_type->cap->edit_others_posts;
// The post is published, extra cap required.
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->edit_published_posts;
} elseif ( 'private' == $post->post_status ) {
$caps[] = $post_type->cap->edit_private_posts;
}
}
break;
case 'read_post':
case 'read_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'read_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
$status_obj = get_post_status_object( $post->post_status );
if ( $status_obj->public ) {
$caps[] = $post_type->cap->read;
break;
}
if ( $post->post_author && $user_id == $post->post_author ) {
$caps[] = $post_type->cap->read;
} elseif ( $status_obj->private ) {
$caps[] = $post_type->cap->read_private_posts;
} else {
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
}
break;
case 'publish_post':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
$caps[] = $post_type->cap->publish_posts;
break;
case 'edit_post_meta':
case 'delete_post_meta':
case 'add_post_meta':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
$meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) {
/**
* Filter whether the user is allowed to add post meta to a post.
*
* The dynamic portion of the hook name, `$meta_key`, refers to the
* meta key passed to {@see map_meta_cap()}.
*
* @since 3.3.0
*
* @param bool $allowed Whether the user can add the post meta. Default false.
* @param string $meta_key The meta key.
* @param int $post_id Post ID.
* @param int $user_id User ID.
* @param string $cap Capability name.
* @param array $caps User capabilities.
*/
$allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
if ( ! $allowed )
$caps[] = $cap;
} elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
$caps[] = $cap;
}
break;
case 'edit_comment':
$comment = get_comment( $args[0] );
if ( ! $comment ) {
$caps[] = 'do_not_allow';
break;
}
$post = get_post( $comment->comment_post_ID );
/*
* If the post doesn't exist, we have an orphaned comment.
* Fall back to the edit_posts capability, instead.
*/
if ( $post ) {
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
} else {
$caps = map_meta_cap( 'edit_posts', $user_id );
}
break;
case 'unfiltered_upload':
if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'unfiltered_html' :
// Disallow unfiltered_html for all users, even admins and super admins.
if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
$caps[] = 'do_not_allow';
elseif ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = $cap;
break;
case 'edit_files':
case 'edit_plugins':
case 'edit_themes':
// Disallow the file editors.
if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT )
$caps[] = 'do_not_allow';
elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
$caps[] = 'do_not_allow';
elseif ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = $cap;
break;
case 'update_plugins':
case 'delete_plugins':
case 'install_plugins':
case 'upload_plugins':
case 'update_themes':
case 'delete_themes':
case 'install_themes':
case 'upload_themes':
case 'update_core':
// Disallow anything that creates, deletes, or updates core, plugin, or theme files.
// Files in uploads are excepted.
if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
$caps[] = 'do_not_allow';
} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
$caps[] = 'do_not_allow';
} elseif ( 'upload_themes' === $cap ) {
$caps[] = 'install_themes';
} elseif ( 'upload_plugins' === $cap ) {
$caps[] = 'install_plugins';
} else {
$caps[] = $cap;
}
break;
case 'activate_plugins':
$caps[] = $cap;
if ( is_multisite() ) {
// update_, install_, and delete_ are handled above with is_super_admin().
$menu_perms = get_site_option( 'menu_items', array() );
if ( empty( $menu_perms['plugins'] ) )
$caps[] = 'manage_network_plugins';
}
break;
case 'delete_user':
case 'delete_users':
// If multisite only super admins can delete users.
if ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = 'delete_users'; // delete_user maps to delete_users.
break;
case 'create_users':
if ( !is_multisite() )
$caps[] = $cap;
elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'manage_links' :
if ( get_option( 'link_manager_enabled' ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'customize' :
$caps[] = 'edit_theme_options';
break;
case 'delete_site':
$caps[] = 'manage_options';
break;
default:
// Handle meta capabilities for custom post types.
$post_type_meta_caps = _post_type_meta_capabilities();
if ( isset( $post_type_meta_caps[ $cap ] ) ) {
$args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
return call_user_func_array( 'map_meta_cap', $args );
}
// If no meta caps match, return the original cap.
$caps[] = $cap;
}
/**
* Filter a user's capabilities depending on specific context and/or privilege.
*
* @since 2.8.0
*
* @param array $caps Returns the user's actual capabilities.
* @param string $cap Capability name.
* @param int $user_id The user ID.
* @param array $args Adds the context to the cap. Typically the object ID.
*/
return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
}
/**
* Whether the current user has a specific capability.
*
* While checking against particular roles in place of a capability is supported
* in part, this practice is discouraged as it may produce unreliable results.
*
* @since 2.0.0
*
* @see WP_User::has_cap()
* @see map_meta_cap()
*
* @param string $capability Capability name.
* @param int $object_id Optional. ID of the specific object to check against if `$capability` is a "meta" cap.
* "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
* by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
* 'edit_others_posts', etc. Accessed via func_get_args() and passed to WP_User::has_cap(),
* then map_meta_cap().
* @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
* passed, whether the current user has the given meta capability for the given object.
*/
function current_user_can( $capability ) {
$current_user = wp_get_current_user();
if ( empty( $current_user ) )
return false;
$args = array_slice( func_get_args(), 1 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $current_user, 'has_cap' ), $args );
}
/**
* Whether current user has a capability or role for a given blog.
*
* @since 3.0.0
*
* @param int $blog_id Blog ID
* @param string $capability Capability or role name.
* @return bool
*/
function current_user_can_for_blog( $blog_id, $capability ) {
$switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
$current_user = wp_get_current_user();
if ( empty( $current_user ) ) {
if ( $switched ) {
restore_current_blog();
}
return false;
}
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
$can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
if ( $switched ) {
restore_current_blog();
}
return $can;
}
/**
* Whether author of supplied post has capability or role.
*
* @since 2.9.0
*
* @param int|object $post Post ID or post object.
* @param string $capability Capability or role name.
* @return bool
*/
function author_can( $post, $capability ) {
if ( !$post = get_post($post) )
return false;
$author = get_userdata( $post->post_author );
if ( ! $author )
return false;
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $author, 'has_cap' ), $args );
}
/**
* Whether a particular user has capability or role.
*
* @since 3.1.0
*
* @param int|object $user User ID or object.
* @param string $capability Capability or role name.
* @return bool
*/
function user_can( $user, $capability ) {
if ( ! is_object( $user ) )
$user = get_userdata( $user );
if ( ! $user || ! $user->exists() )
return false;
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $user, 'has_cap' ), $args );
}
/**
* Retrieves the global WP_Roles instance and instantiates it if necessary.
*
* @since 4.3.0
*
* @global WP_Roles $wp_roles WP_Roles global instance.
*
* @return WP_Roles WP_Roles global instance if not already instantiated.
*/
function wp_roles() {
global $wp_roles;
if ( ! isset( $wp_roles ) ) {
$wp_roles = new WP_Roles();
}
return $wp_roles;
}
/**
* Retrieve role object.
*
* @since 2.0.0
*
* @param string $role Role name.
* @return WP_Role|null WP_Role object if found, null if the role does not exist.
*/
function get_role( $role ) {
return wp_roles()->get_role( $role );
}
/**
* Add role, if it does not exist.
*
* @since 2.0.0
*
* @param string $role Role name.
* @param string $display_name Display name for role.
* @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
* @return WP_Role|null WP_Role object if role is added, null if already exists.
*/
function add_role( $role, $display_name, $capabilities = array() ) {
if ( empty( $role ) ) {
return;
}
return wp_roles()->add_role( $role, $display_name, $capabilities );
}
/**
* Remove role, if it exists.
*
* @since 2.0.0
*
* @param string $role Role name.
*/
function remove_role( $role ) {
wp_roles()->remove_role( $role );
}
/**
* Retrieve a list of super admins.
*
* @since 3.0.0
*
* @global array $super_admins
*
* @return array List of super admin logins
*/
function get_super_admins() {
global $super_admins;
if ( isset($super_admins) )
return $super_admins;
else
return get_site_option( 'site_admins', array('admin') );
}
/**
* Determine if user is a site admin.
*
* @since 3.0.0
*
* @param int $user_id (Optional) The ID of a user. Defaults to the current user.
* @return bool True if the user is a site admin.
*/
function is_super_admin( $user_id = false ) {
if ( ! $user_id || $user_id == get_current_user_id() )
$user = wp_get_current_user();
else
$user = get_userdata( $user_id );
if ( ! $user || ! $user->exists() )
return false;
if ( is_multisite() ) {
$super_admins = get_super_admins();
if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) )
return true;
} else {
if ( $user->has_cap('delete_users') )
return true;
}
return false;
}

View File

@ -4,17 +4,608 @@
*
* @package WordPress
* @subpackage Users
* @since 2.0.0
*/
/** WP_Roles class */
require_once( ABSPATH . WPINC . '/class-wp-roles.php' );
/**
* Map meta capabilities to primitive capabilities.
*
* This does not actually compare whether the user ID has the actual capability,
* just what the capability or capabilities are. Meta capability list value can
* be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
* 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
*
* @since 2.0.0
*
* @param string $cap Capability name.
* @param int $user_id User ID.
* @param int $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
* "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
* by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
* 'edit_others_posts', etc. The parameter is accessed via func_get_args().
* @return array Actual capabilities for meta capability.
*/
function map_meta_cap( $cap, $user_id ) {
$args = array_slice( func_get_args(), 2 );
$caps = array();
/** WP_Role class */
require_once( ABSPATH . WPINC . '/class-wp-role.php' );
switch ( $cap ) {
case 'remove_user':
$caps[] = 'remove_users';
break;
case 'promote_user':
case 'add_users':
$caps[] = 'promote_users';
break;
case 'edit_user':
case 'edit_users':
// Allow user to edit itself
if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] )
break;
/** WP_User class */
require_once( ABSPATH . WPINC . '/class-wp-user.php' );
// In multisite the user must have manage_network_users caps. If editing a super admin, the user must be a super admin.
if ( is_multisite() && ( ( ! is_super_admin( $user_id ) && 'edit_user' === $cap && is_super_admin( $args[0] ) ) || ! user_can( $user_id, 'manage_network_users' ) ) ) {
$caps[] = 'do_not_allow';
} else {
$caps[] = 'edit_users'; // edit_user maps to edit_users.
}
break;
case 'delete_post':
case 'delete_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
/** Core capabilities functionality */
require_once( ABSPATH . WPINC . '/capabilities-functions.php' );
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'delete_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
// If the post author is set and the user is the author...
if ( $post->post_author && $user_id == $post->post_author ) {
// If the post is published...
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->delete_published_posts;
} elseif ( 'trash' == $post->post_status ) {
if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
$caps[] = $post_type->cap->delete_published_posts;
}
} else {
// If the post is draft...
$caps[] = $post_type->cap->delete_posts;
}
} else {
// The user is trying to edit someone else's post.
$caps[] = $post_type->cap->delete_others_posts;
// The post is published, extra cap required.
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->delete_published_posts;
} elseif ( 'private' == $post->post_status ) {
$caps[] = $post_type->cap->delete_private_posts;
}
}
break;
// edit_post breaks down to edit_posts, edit_published_posts, or
// edit_others_posts
case 'edit_post':
case 'edit_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'edit_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
// If the post author is set and the user is the author...
if ( $post->post_author && $user_id == $post->post_author ) {
// If the post is published...
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->edit_published_posts;
} elseif ( 'trash' == $post->post_status ) {
if ( 'publish' == get_post_meta( $post->ID, '_wp_trash_meta_status', true ) ) {
$caps[] = $post_type->cap->edit_published_posts;
}
} else {
// If the post is draft...
$caps[] = $post_type->cap->edit_posts;
}
} else {
// The user is trying to edit someone else's post.
$caps[] = $post_type->cap->edit_others_posts;
// The post is published, extra cap required.
if ( 'publish' == $post->post_status ) {
$caps[] = $post_type->cap->edit_published_posts;
} elseif ( 'private' == $post->post_status ) {
$caps[] = $post_type->cap->edit_private_posts;
}
}
break;
case 'read_post':
case 'read_page':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
if ( 'revision' == $post->post_type ) {
$post = get_post( $post->post_parent );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
if ( ! $post_type->map_meta_cap ) {
$caps[] = $post_type->cap->$cap;
// Prior to 3.1 we would re-call map_meta_cap here.
if ( 'read_post' == $cap )
$cap = $post_type->cap->$cap;
break;
}
$status_obj = get_post_status_object( $post->post_status );
if ( $status_obj->public ) {
$caps[] = $post_type->cap->read;
break;
}
if ( $post->post_author && $user_id == $post->post_author ) {
$caps[] = $post_type->cap->read;
} elseif ( $status_obj->private ) {
$caps[] = $post_type->cap->read_private_posts;
} else {
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
}
break;
case 'publish_post':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
$post_type = get_post_type_object( $post->post_type );
if ( ! $post_type ) {
/* translators: 1: post type, 2: capability name */
_doing_it_wrong( __FUNCTION__, sprintf( __( 'The post type %1$s is not registered, so it may not be reliable to check the capability "%2$s" against a post of that type.' ), $post->post_type, $cap ), '4.4.0' );
$caps[] = 'edit_others_posts';
break;
}
$caps[] = $post_type->cap->publish_posts;
break;
case 'edit_post_meta':
case 'delete_post_meta':
case 'add_post_meta':
$post = get_post( $args[0] );
if ( ! $post ) {
$caps[] = 'do_not_allow';
break;
}
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
$meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) {
/**
* Filter whether the user is allowed to add post meta to a post.
*
* The dynamic portion of the hook name, `$meta_key`, refers to the
* meta key passed to {@see map_meta_cap()}.
*
* @since 3.3.0
*
* @param bool $allowed Whether the user can add the post meta. Default false.
* @param string $meta_key The meta key.
* @param int $post_id Post ID.
* @param int $user_id User ID.
* @param string $cap Capability name.
* @param array $caps User capabilities.
*/
$allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
if ( ! $allowed )
$caps[] = $cap;
} elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
$caps[] = $cap;
}
break;
case 'edit_comment':
$comment = get_comment( $args[0] );
if ( ! $comment ) {
$caps[] = 'do_not_allow';
break;
}
$post = get_post( $comment->comment_post_ID );
/*
* If the post doesn't exist, we have an orphaned comment.
* Fall back to the edit_posts capability, instead.
*/
if ( $post ) {
$caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
} else {
$caps = map_meta_cap( 'edit_posts', $user_id );
}
break;
case 'unfiltered_upload':
if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'unfiltered_html' :
// Disallow unfiltered_html for all users, even admins and super admins.
if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
$caps[] = 'do_not_allow';
elseif ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = $cap;
break;
case 'edit_files':
case 'edit_plugins':
case 'edit_themes':
// Disallow the file editors.
if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT )
$caps[] = 'do_not_allow';
elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
$caps[] = 'do_not_allow';
elseif ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = $cap;
break;
case 'update_plugins':
case 'delete_plugins':
case 'install_plugins':
case 'upload_plugins':
case 'update_themes':
case 'delete_themes':
case 'install_themes':
case 'upload_themes':
case 'update_core':
// Disallow anything that creates, deletes, or updates core, plugin, or theme files.
// Files in uploads are excepted.
if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
$caps[] = 'do_not_allow';
} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
$caps[] = 'do_not_allow';
} elseif ( 'upload_themes' === $cap ) {
$caps[] = 'install_themes';
} elseif ( 'upload_plugins' === $cap ) {
$caps[] = 'install_plugins';
} else {
$caps[] = $cap;
}
break;
case 'activate_plugins':
$caps[] = $cap;
if ( is_multisite() ) {
// update_, install_, and delete_ are handled above with is_super_admin().
$menu_perms = get_site_option( 'menu_items', array() );
if ( empty( $menu_perms['plugins'] ) )
$caps[] = 'manage_network_plugins';
}
break;
case 'delete_user':
case 'delete_users':
// If multisite only super admins can delete users.
if ( is_multisite() && ! is_super_admin( $user_id ) )
$caps[] = 'do_not_allow';
else
$caps[] = 'delete_users'; // delete_user maps to delete_users.
break;
case 'create_users':
if ( !is_multisite() )
$caps[] = $cap;
elseif ( is_super_admin( $user_id ) || get_site_option( 'add_new_users' ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'manage_links' :
if ( get_option( 'link_manager_enabled' ) )
$caps[] = $cap;
else
$caps[] = 'do_not_allow';
break;
case 'customize' :
$caps[] = 'edit_theme_options';
break;
case 'delete_site':
$caps[] = 'manage_options';
break;
default:
// Handle meta capabilities for custom post types.
$post_type_meta_caps = _post_type_meta_capabilities();
if ( isset( $post_type_meta_caps[ $cap ] ) ) {
$args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
return call_user_func_array( 'map_meta_cap', $args );
}
// If no meta caps match, return the original cap.
$caps[] = $cap;
}
/**
* Filter a user's capabilities depending on specific context and/or privilege.
*
* @since 2.8.0
*
* @param array $caps Returns the user's actual capabilities.
* @param string $cap Capability name.
* @param int $user_id The user ID.
* @param array $args Adds the context to the cap. Typically the object ID.
*/
return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
}
/**
* Whether the current user has a specific capability.
*
* While checking against particular roles in place of a capability is supported
* in part, this practice is discouraged as it may produce unreliable results.
*
* @since 2.0.0
*
* @see WP_User::has_cap()
* @see map_meta_cap()
*
* @param string $capability Capability name.
* @param int $object_id Optional. ID of the specific object to check against if `$capability` is a "meta" cap.
* "Meta" capabilities, e.g. 'edit_post', 'edit_user', etc., are capabilities used
* by map_meta_cap() to map to other "primitive" capabilities, e.g. 'edit_posts',
* 'edit_others_posts', etc. Accessed via func_get_args() and passed to WP_User::has_cap(),
* then map_meta_cap().
* @return bool Whether the current user has the given capability. If `$capability` is a meta cap and `$object_id` is
* passed, whether the current user has the given meta capability for the given object.
*/
function current_user_can( $capability ) {
$current_user = wp_get_current_user();
if ( empty( $current_user ) )
return false;
$args = array_slice( func_get_args(), 1 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $current_user, 'has_cap' ), $args );
}
/**
* Whether current user has a capability or role for a given blog.
*
* @since 3.0.0
*
* @param int $blog_id Blog ID
* @param string $capability Capability or role name.
* @return bool
*/
function current_user_can_for_blog( $blog_id, $capability ) {
$switched = is_multisite() ? switch_to_blog( $blog_id ) : false;
$current_user = wp_get_current_user();
if ( empty( $current_user ) ) {
if ( $switched ) {
restore_current_blog();
}
return false;
}
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
$can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
if ( $switched ) {
restore_current_blog();
}
return $can;
}
/**
* Whether author of supplied post has capability or role.
*
* @since 2.9.0
*
* @param int|object $post Post ID or post object.
* @param string $capability Capability or role name.
* @return bool
*/
function author_can( $post, $capability ) {
if ( !$post = get_post($post) )
return false;
$author = get_userdata( $post->post_author );
if ( ! $author )
return false;
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $author, 'has_cap' ), $args );
}
/**
* Whether a particular user has capability or role.
*
* @since 3.1.0
*
* @param int|object $user User ID or object.
* @param string $capability Capability or role name.
* @return bool
*/
function user_can( $user, $capability ) {
if ( ! is_object( $user ) )
$user = get_userdata( $user );
if ( ! $user || ! $user->exists() )
return false;
$args = array_slice( func_get_args(), 2 );
$args = array_merge( array( $capability ), $args );
return call_user_func_array( array( $user, 'has_cap' ), $args );
}
/**
* Retrieves the global WP_Roles instance and instantiates it if necessary.
*
* @since 4.3.0
*
* @global WP_Roles $wp_roles WP_Roles global instance.
*
* @return WP_Roles WP_Roles global instance if not already instantiated.
*/
function wp_roles() {
global $wp_roles;
if ( ! isset( $wp_roles ) ) {
$wp_roles = new WP_Roles();
}
return $wp_roles;
}
/**
* Retrieve role object.
*
* @since 2.0.0
*
* @param string $role Role name.
* @return WP_Role|null WP_Role object if found, null if the role does not exist.
*/
function get_role( $role ) {
return wp_roles()->get_role( $role );
}
/**
* Add role, if it does not exist.
*
* @since 2.0.0
*
* @param string $role Role name.
* @param string $display_name Display name for role.
* @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
* @return WP_Role|null WP_Role object if role is added, null if already exists.
*/
function add_role( $role, $display_name, $capabilities = array() ) {
if ( empty( $role ) ) {
return;
}
return wp_roles()->add_role( $role, $display_name, $capabilities );
}
/**
* Remove role, if it exists.
*
* @since 2.0.0
*
* @param string $role Role name.
*/
function remove_role( $role ) {
wp_roles()->remove_role( $role );
}
/**
* Retrieve a list of super admins.
*
* @since 3.0.0
*
* @global array $super_admins
*
* @return array List of super admin logins
*/
function get_super_admins() {
global $super_admins;
if ( isset($super_admins) )
return $super_admins;
else
return get_site_option( 'site_admins', array('admin') );
}
/**
* Determine if user is a site admin.
*
* @since 3.0.0
*
* @param int $user_id (Optional) The ID of a user. Defaults to the current user.
* @return bool True if the user is a site admin.
*/
function is_super_admin( $user_id = false ) {
if ( ! $user_id || $user_id == get_current_user_id() )
$user = wp_get_current_user();
else
$user = get_userdata( $user_id );
if ( ! $user || ! $user->exists() )
return false;
if ( is_multisite() ) {
$super_admins = get_super_admins();
if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) )
return true;
} else {
if ( $user->has_cap('delete_users') )
return true;
}
return false;
}

View File

@ -1,349 +0,0 @@
<?php
/**
* Taxonomy API: Top-level core category-specific functionality
*
* @package WordPress
* @subpackage Taxonomy
* @since 4.4.0
*/
/**
* Retrieve list of category objects.
*
* If you change the type to 'link' in the arguments, then the link categories
* will be returned instead. Also all categories will be updated to be backwards
* compatible with pre-2.3 plugins and themes.
*
* @since 2.1.0
* @see get_terms() Type of arguments that can be changed.
* @link https://codex.wordpress.org/Function_Reference/get_categories
*
* @param string|array $args Optional. Change the defaults retrieving categories.
* @return array List of categories.
*/
function get_categories( $args = '' ) {
$defaults = array( 'taxonomy' => 'category' );
$args = wp_parse_args( $args, $defaults );
$taxonomy = $args['taxonomy'];
/**
* Filter the taxonomy used to retrieve terms when calling {@see get_categories()}.
*
* @since 2.7.0
*
* @param string $taxonomy Taxonomy to retrieve terms from.
* @param array $args An array of arguments. See {@see get_terms()}.
*/
$taxonomy = apply_filters( 'get_categories_taxonomy', $taxonomy, $args );
// Back compat
if ( isset($args['type']) && 'link' == $args['type'] ) {
/* translators: 1: "type => link", 2: "taxonomy => link_category" alternative */
_deprecated_argument( __FUNCTION__, '3.0',
sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
'<code>type => link</code>',
'<code>taxonomy => link_category</code>'
)
);
$taxonomy = $args['taxonomy'] = 'link_category';
}
$categories = (array) get_terms( $taxonomy, $args );
foreach ( array_keys( $categories ) as $k )
_make_cat_compat( $categories[$k] );
return $categories;
}
/**
* Retrieves category data given a category ID or category object.
*
* If you pass the $category parameter an object, which is assumed to be the
* category row object retrieved the database. It will cache the category data.
*
* If you pass $category an integer of the category ID, then that category will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* The category will converted to maintain backwards compatibility.
*
* @since 1.5.1
*
* @param int|object $category Category ID or Category row object
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return object|array|WP_Error|null Category data in type defined by $output parameter.
* WP_Error if $category is empty, null if it does not exist.
*/
function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
$category = get_term( $category, 'category', $output, $filter );
if ( is_wp_error( $category ) )
return $category;
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve category based on URL containing the category slug.
*
* Breaks the $category_path parameter up to get the category slug.
*
* Tries to find the child path and will return it. If it doesn't find a
* match, then it will return the first category matching slug, if $full_match,
* is set to false. If it does not, then it will return null.
*
* It is also possible that it will return a WP_Error object on failure. Check
* for it when using this function.
*
* @since 2.1.0
*
* @param string $category_path URL containing category slugs.
* @param bool $full_match Optional. Whether full path should be matched.
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @return object|array|WP_Error|void Type is based on $output value.
*/
function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
$category_path = rawurlencode( urldecode( $category_path ) );
$category_path = str_replace( '%2F', '/', $category_path );
$category_path = str_replace( '%20', ' ', $category_path );
$category_paths = '/' . trim( $category_path, '/' );
$leaf_path = sanitize_title( basename( $category_paths ) );
$category_paths = explode( '/', $category_paths );
$full_path = '';
foreach ( (array) $category_paths as $pathdir ) {
$full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
}
$categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
if ( empty( $categories ) ) {
return;
}
foreach ( $categories as $category ) {
$path = '/' . $leaf_path;
$curcategory = $category;
while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
$curcategory = get_term( $curcategory->parent, 'category' );
if ( is_wp_error( $curcategory ) ) {
return $curcategory;
}
$path = '/' . $curcategory->slug . $path;
}
if ( $path == $full_path ) {
$category = get_term( $category->term_id, 'category', $output );
_make_cat_compat( $category );
return $category;
}
}
// If full matching is not required, return the first cat that matches the leaf.
if ( ! $full_match ) {
$category = get_term( reset( $categories )->term_id, 'category', $output );
_make_cat_compat( $category );
return $category;
}
}
/**
* Retrieve category object by category slug.
*
* @since 2.3.0
*
* @param string $slug The category slug.
* @return object Category data object
*/
function get_category_by_slug( $slug ) {
$category = get_term_by( 'slug', $slug, 'category' );
if ( $category )
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve the ID of a category from its name.
*
* @since 1.0.0
*
* @param string $cat_name Category name.
* @return int 0, if failure and ID of category on success.
*/
function get_cat_ID( $cat_name ) {
$cat = get_term_by( 'name', $cat_name, 'category' );
if ( $cat )
return $cat->term_id;
return 0;
}
/**
* Retrieve the name of a category from its ID.
*
* @since 1.0.0
*
* @param int $cat_id Category ID
* @return string Category name, or an empty string if category doesn't exist.
*/
function get_cat_name( $cat_id ) {
$cat_id = (int) $cat_id;
$category = get_term( $cat_id, 'category' );
if ( ! $category || is_wp_error( $category ) )
return '';
return $category->name;
}
/**
* Check if a category is an ancestor of another category.
*
* You can use either an id or the category object for both parameters. If you
* use an integer the category will be retrieved.
*
* @since 2.1.0
*
* @param int|object $cat1 ID or object to check if this is the parent category.
* @param int|object $cat2 The child category.
* @return bool Whether $cat2 is child of $cat1
*/
function cat_is_ancestor_of( $cat1, $cat2 ) {
return term_is_ancestor_of( $cat1, $cat2, 'category' );
}
/**
* Sanitizes category data based on context.
*
* @since 2.3.0
*
* @param object|array $category Category data
* @param string $context Optional. Default is 'display'.
* @return object|array Same type as $category with sanitized data for safe use.
*/
function sanitize_category( $category, $context = 'display' ) {
return sanitize_term( $category, 'category', $context );
}
/**
* Sanitizes data in single category key field.
*
* @since 2.3.0
*
* @param string $field Category key to sanitize
* @param mixed $value Category value to sanitize
* @param int $cat_id Category ID
* @param string $context What filter to use, 'raw', 'display', etc.
* @return mixed Same type as $value after $value has been sanitized.
*/
function sanitize_category_field( $field, $value, $cat_id, $context ) {
return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
}
/* Tags */
/**
* Retrieves all post tags.
*
* @since 2.3.0
* @see get_terms() For list of arguments to pass.
*
* @param string|array $args Tag arguments to use when retrieving tags.
* @return array List of tags.
*/
function get_tags( $args = '' ) {
$tags = get_terms( 'post_tag', $args );
if ( empty( $tags ) ) {
$return = array();
return $return;
}
/**
* Filter the array of term objects returned for the 'post_tag' taxonomy.
*
* @since 2.3.0
*
* @param array $tags Array of 'post_tag' term objects.
* @param array $args An array of arguments. @see get_terms()
*/
$tags = apply_filters( 'get_tags', $tags, $args );
return $tags;
}
/**
* Retrieve post tag by tag ID or tag object.
*
* If you pass the $tag parameter an object, which is assumed to be the tag row
* object retrieved the database. It will cache the tag data.
*
* If you pass $tag an integer of the tag ID, then that tag will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* @since 2.3.0
*
* @param int|object $tag
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return object|array|WP_Error|null Tag data in type defined by $output parameter. WP_Error if $tag is empty, null if it does not exist.
*/
function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
return get_term( $tag, 'post_tag', $output, $filter );
}
/* Cache */
/**
* Remove the category cache data based on ID.
*
* @since 2.1.0
*
* @param int $id Category ID
*/
function clean_category_cache( $id ) {
clean_term_cache( $id, 'category' );
}
/**
* Update category structure to old pre 2.3 from new taxonomy structure.
*
* This function was added for the taxonomy support to update the new category
* structure with the old category one. This will maintain compatibility with
* plugins and themes which depend on the old key or property names.
*
* The parameter should only be passed a variable and not create the array or
* object inline to the parameter. The reason for this is that parameter is
* passed by reference and PHP will fail unless it has the variable.
*
* There is no return value, because everything is updated on the variable you
* pass to it. This is one of the features with using pass by reference in PHP.
*
* @since 2.3.0
* @since 4.4.0 The `$category` parameter now also accepts a WP_Term object.
* @access private
*
* @param array|object|WP_Term $category Category Row object or array
*/
function _make_cat_compat( &$category ) {
if ( is_object( $category ) && ! is_wp_error( $category ) ) {
$category->cat_ID = $category->term_id;
$category->category_count = $category->count;
$category->category_description = $category->description;
$category->cat_name = $category->name;
$category->category_nicename = $category->slug;
$category->category_parent = $category->parent;
} elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
$category['cat_ID'] = &$category['term_id'];
$category['category_count'] = &$category['count'];
$category['category_description'] = &$category['description'];
$category['cat_name'] = &$category['name'];
$category['category_nicename'] = &$category['slug'];
$category['category_parent'] = &$category['parent'];
}
}

View File

@ -4,14 +4,345 @@
*
* @package WordPress
* @subpackage Taxonomy
* @since 2.1.0
*/
/** Core category functionality */
require_once( ABSPATH . WPINC . '/category-functions.php' );
/**
* Retrieve list of category objects.
*
* If you change the type to 'link' in the arguments, then the link categories
* will be returned instead. Also all categories will be updated to be backwards
* compatible with pre-2.3 plugins and themes.
*
* @since 2.1.0
* @see get_terms() Type of arguments that can be changed.
* @link https://codex.wordpress.org/Function_Reference/get_categories
*
* @param string|array $args Optional. Change the defaults retrieving categories.
* @return array List of categories.
*/
function get_categories( $args = '' ) {
$defaults = array( 'taxonomy' => 'category' );
$args = wp_parse_args( $args, $defaults );
/** Walker_Category class */
require_once( ABSPATH . WPINC . '/class-walker-category.php' );
$taxonomy = $args['taxonomy'];
/** Walker_CategoryDropdown class */
require_once( ABSPATH . WPINC . '/class-walker-category-dropdown.php' );
/**
* Filter the taxonomy used to retrieve terms when calling {@see get_categories()}.
*
* @since 2.7.0
*
* @param string $taxonomy Taxonomy to retrieve terms from.
* @param array $args An array of arguments. See {@see get_terms()}.
*/
$taxonomy = apply_filters( 'get_categories_taxonomy', $taxonomy, $args );
// Back compat
if ( isset($args['type']) && 'link' == $args['type'] ) {
/* translators: 1: "type => link", 2: "taxonomy => link_category" alternative */
_deprecated_argument( __FUNCTION__, '3.0',
sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
'<code>type => link</code>',
'<code>taxonomy => link_category</code>'
)
);
$taxonomy = $args['taxonomy'] = 'link_category';
}
$categories = (array) get_terms( $taxonomy, $args );
foreach ( array_keys( $categories ) as $k )
_make_cat_compat( $categories[$k] );
return $categories;
}
/**
* Retrieves category data given a category ID or category object.
*
* If you pass the $category parameter an object, which is assumed to be the
* category row object retrieved the database. It will cache the category data.
*
* If you pass $category an integer of the category ID, then that category will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* The category will converted to maintain backwards compatibility.
*
* @since 1.5.1
*
* @param int|object $category Category ID or Category row object
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return object|array|WP_Error|null Category data in type defined by $output parameter.
* WP_Error if $category is empty, null if it does not exist.
*/
function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
$category = get_term( $category, 'category', $output, $filter );
if ( is_wp_error( $category ) )
return $category;
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve category based on URL containing the category slug.
*
* Breaks the $category_path parameter up to get the category slug.
*
* Tries to find the child path and will return it. If it doesn't find a
* match, then it will return the first category matching slug, if $full_match,
* is set to false. If it does not, then it will return null.
*
* It is also possible that it will return a WP_Error object on failure. Check
* for it when using this function.
*
* @since 2.1.0
*
* @param string $category_path URL containing category slugs.
* @param bool $full_match Optional. Whether full path should be matched.
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @return object|array|WP_Error|void Type is based on $output value.
*/
function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
$category_path = rawurlencode( urldecode( $category_path ) );
$category_path = str_replace( '%2F', '/', $category_path );
$category_path = str_replace( '%20', ' ', $category_path );
$category_paths = '/' . trim( $category_path, '/' );
$leaf_path = sanitize_title( basename( $category_paths ) );
$category_paths = explode( '/', $category_paths );
$full_path = '';
foreach ( (array) $category_paths as $pathdir ) {
$full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
}
$categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
if ( empty( $categories ) ) {
return;
}
foreach ( $categories as $category ) {
$path = '/' . $leaf_path;
$curcategory = $category;
while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
$curcategory = get_term( $curcategory->parent, 'category' );
if ( is_wp_error( $curcategory ) ) {
return $curcategory;
}
$path = '/' . $curcategory->slug . $path;
}
if ( $path == $full_path ) {
$category = get_term( $category->term_id, 'category', $output );
_make_cat_compat( $category );
return $category;
}
}
// If full matching is not required, return the first cat that matches the leaf.
if ( ! $full_match ) {
$category = get_term( reset( $categories )->term_id, 'category', $output );
_make_cat_compat( $category );
return $category;
}
}
/**
* Retrieve category object by category slug.
*
* @since 2.3.0
*
* @param string $slug The category slug.
* @return object Category data object
*/
function get_category_by_slug( $slug ) {
$category = get_term_by( 'slug', $slug, 'category' );
if ( $category )
_make_cat_compat( $category );
return $category;
}
/**
* Retrieve the ID of a category from its name.
*
* @since 1.0.0
*
* @param string $cat_name Category name.
* @return int 0, if failure and ID of category on success.
*/
function get_cat_ID( $cat_name ) {
$cat = get_term_by( 'name', $cat_name, 'category' );
if ( $cat )
return $cat->term_id;
return 0;
}
/**
* Retrieve the name of a category from its ID.
*
* @since 1.0.0
*
* @param int $cat_id Category ID
* @return string Category name, or an empty string if category doesn't exist.
*/
function get_cat_name( $cat_id ) {
$cat_id = (int) $cat_id;
$category = get_term( $cat_id, 'category' );
if ( ! $category || is_wp_error( $category ) )
return '';
return $category->name;
}
/**
* Check if a category is an ancestor of another category.
*
* You can use either an id or the category object for both parameters. If you
* use an integer the category will be retrieved.
*
* @since 2.1.0
*
* @param int|object $cat1 ID or object to check if this is the parent category.
* @param int|object $cat2 The child category.
* @return bool Whether $cat2 is child of $cat1
*/
function cat_is_ancestor_of( $cat1, $cat2 ) {
return term_is_ancestor_of( $cat1, $cat2, 'category' );
}
/**
* Sanitizes category data based on context.
*
* @since 2.3.0
*
* @param object|array $category Category data
* @param string $context Optional. Default is 'display'.
* @return object|array Same type as $category with sanitized data for safe use.
*/
function sanitize_category( $category, $context = 'display' ) {
return sanitize_term( $category, 'category', $context );
}
/**
* Sanitizes data in single category key field.
*
* @since 2.3.0
*
* @param string $field Category key to sanitize
* @param mixed $value Category value to sanitize
* @param int $cat_id Category ID
* @param string $context What filter to use, 'raw', 'display', etc.
* @return mixed Same type as $value after $value has been sanitized.
*/
function sanitize_category_field( $field, $value, $cat_id, $context ) {
return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
}
/* Tags */
/**
* Retrieves all post tags.
*
* @since 2.3.0
* @see get_terms() For list of arguments to pass.
*
* @param string|array $args Tag arguments to use when retrieving tags.
* @return array List of tags.
*/
function get_tags( $args = '' ) {
$tags = get_terms( 'post_tag', $args );
if ( empty( $tags ) ) {
$return = array();
return $return;
}
/**
* Filter the array of term objects returned for the 'post_tag' taxonomy.
*
* @since 2.3.0
*
* @param array $tags Array of 'post_tag' term objects.
* @param array $args An array of arguments. @see get_terms()
*/
$tags = apply_filters( 'get_tags', $tags, $args );
return $tags;
}
/**
* Retrieve post tag by tag ID or tag object.
*
* If you pass the $tag parameter an object, which is assumed to be the tag row
* object retrieved the database. It will cache the tag data.
*
* If you pass $tag an integer of the tag ID, then that tag will
* be retrieved from the database, if it isn't already cached, and pass it back.
*
* If you look at get_term(), then both types will be passed through several
* filters and finally sanitized based on the $filter parameter value.
*
* @since 2.3.0
*
* @param int|object $tag
* @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
* @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
* @return object|array|WP_Error|null Tag data in type defined by $output parameter. WP_Error if $tag is empty, null if it does not exist.
*/
function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
return get_term( $tag, 'post_tag', $output, $filter );
}
/* Cache */
/**
* Remove the category cache data based on ID.
*
* @since 2.1.0
*
* @param int $id Category ID
*/
function clean_category_cache( $id ) {
clean_term_cache( $id, 'category' );
}
/**
* Update category structure to old pre 2.3 from new taxonomy structure.
*
* This function was added for the taxonomy support to update the new category
* structure with the old category one. This will maintain compatibility with
* plugins and themes which depend on the old key or property names.
*
* The parameter should only be passed a variable and not create the array or
* object inline to the parameter. The reason for this is that parameter is
* passed by reference and PHP will fail unless it has the variable.
*
* There is no return value, because everything is updated on the variable you
* pass to it. This is one of the features with using pass by reference in PHP.
*
* @since 2.3.0
* @since 4.4.0 The `$category` parameter now also accepts a WP_Term object.
* @access private
*
* @param array|object|WP_Term $category Category Row object or array
*/
function _make_cat_compat( &$category ) {
if ( is_object( $category ) && ! is_wp_error( $category ) ) {
$category->cat_ID = $category->term_id;
$category->category_count = $category->count;
$category->category_description = $category->description;
$category->cat_name = $category->name;
$category->category_nicename = $category->slug;
$category->category_parent = $category->parent;
} elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
$category['cat_ID'] = &$category['term_id'];
$category['category_count'] = &$category['count'];
$category['category_description'] = &$category['description'];
$category['cat_name'] = &$category['name'];
$category['category_nicename'] = &$category['slug'];
$category['category_parent'] = &$category['parent'];
}
}

View File

@ -192,6 +192,37 @@ final class WP_Customize_Manager {
require_once( ABSPATH . WPINC . '/class-wp-customize-section.php' );
require_once( ABSPATH . WPINC . '/class-wp-customize-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-color-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-media-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-upload-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-image-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-cropped-image-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-site-icon-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-theme-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-widget-area-customize-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-widget-form-customize-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-location-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menus-panel.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-themes-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-sidebar-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-filter-setting.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-header-image-setting.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-background-image-setting.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-setting.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-setting.php' );
/**
* Filter the core Customizer components to load.
*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,660 +0,0 @@
<?php
/**
* HTTP API: Top-level HTTP request API functionality
*
* @package WordPress
* @subpackage HTTP
* @since 4.4.0
*/
/**
* Returns the initialized WP_Http Object
*
* @since 2.7.0
* @access private
*
* @staticvar WP_Http $http
*
* @return WP_Http HTTP Transport object.
*/
function _wp_http_get_object() {
static $http = null;
if ( is_null( $http ) ) {
$http = new WP_Http();
}
return $http;
}
/**
* Retrieve the raw response from a safe HTTP request.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_request( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/**
* Retrieve the raw response from a safe HTTP request using the GET method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_get( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/**
* Retrieve the raw response from a safe HTTP request using the POST method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_post( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/**
* Retrieve the raw response from a safe HTTP request using the HEAD method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_head( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request.
*
* The array structure is a little complex:
*
* $res = array(
* 'headers' => array(),
* 'response' => array(
* 'code' => int,
* 'message' => string
* )
* );
*
* All of the headers in $res['headers'] are with the name as the key and the
* value as the value. So to get the User-Agent, you would do the following.
*
* $user_agent = $res['headers']['user-agent'];
*
* The body is the raw response content and can be retrieved from $res['body'].
*
* This function is called first to make the request and there are other API
* functions to abstract out the above convoluted setup.
*
* Request method defaults for helper functions:
* - Default 'GET' for wp_remote_get()
* - Default 'POST' for wp_remote_post()
* - Default 'HEAD' for wp_remote_head()
*
* @since 2.7.0
*
* @see WP_Http::request() For additional information on default arguments.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_request($url, $args = array()) {
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request using the GET method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_get($url, $args = array()) {
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request using the POST method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_post($url, $args = array()) {
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request using the HEAD method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_head($url, $args = array()) {
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/**
* Retrieve only the headers from the raw response.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return array The headers of the response. Empty array if incorrect parameter given.
*/
function wp_remote_retrieve_headers( $response ) {
if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
return array();
return $response['headers'];
}
/**
* Retrieve a single header by name from the raw response.
*
* @since 2.7.0
*
* @param array $response
* @param string $header Header name to retrieve value from.
* @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
*/
function wp_remote_retrieve_header( $response, $header ) {
if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
return '';
if ( array_key_exists($header, $response['headers']) )
return $response['headers'][$header];
return '';
}
/**
* Retrieve only the response code from the raw response.
*
* Will return an empty array if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return int|string The response code as an integer. Empty string on incorrect parameter given.
*/
function wp_remote_retrieve_response_code( $response ) {
if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
return '';
return $response['response']['code'];
}
/**
* Retrieve only the response message from the raw response.
*
* Will return an empty array if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return string The response message. Empty string on incorrect parameter given.
*/
function wp_remote_retrieve_response_message( $response ) {
if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
return '';
return $response['response']['message'];
}
/**
* Retrieve only the body from the raw response.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return string The body of the response. Empty string if no body or incorrect parameter given.
*/
function wp_remote_retrieve_body( $response ) {
if ( is_wp_error($response) || ! isset($response['body']) )
return '';
return $response['body'];
}
/**
* Retrieve only the body from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @return array An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error.
*/
function wp_remote_retrieve_cookies( $response ) {
if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
return array();
}
return $response['cookies'];
}
/**
* Retrieve a single cookie by name from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response.
*/
function wp_remote_retrieve_cookie( $response, $name ) {
$cookies = wp_remote_retrieve_cookies( $response );
if ( empty( $cookies ) ) {
return '';
}
foreach ( $cookies as $cookie ) {
if ( $cookie->name === $name ) {
return $cookie;
}
}
return '';
}
/**
* Retrieve a single cookie's value by name from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return string The value of the cookie. Empty string if the cookie isn't present in the response.
*/
function wp_remote_retrieve_cookie_value( $response, $name ) {
$cookie = wp_remote_retrieve_cookie( $response, $name );
if ( ! is_a( $cookie, 'WP_Http_Cookie' ) ) {
return '';
}
return $cookie->value;
}
/**
* Determines if there is an HTTP Transport that can process this request.
*
* @since 3.2.0
*
* @param array $capabilities Array of capabilities to test or a wp_remote_request() $args array.
* @param string $url Optional. If given, will check if the URL requires SSL and adds
* that requirement to the capabilities array.
*
* @return bool
*/
function wp_http_supports( $capabilities = array(), $url = null ) {
$http = _wp_http_get_object();
$capabilities = wp_parse_args( $capabilities );
$count = count( $capabilities );
// If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
$capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
}
if ( $url && !isset( $capabilities['ssl'] ) ) {
$scheme = parse_url( $url, PHP_URL_SCHEME );
if ( 'https' == $scheme || 'ssl' == $scheme ) {
$capabilities['ssl'] = true;
}
}
return (bool) $http->_get_first_available_transport( $capabilities );
}
/**
* Get the HTTP Origin of the current request.
*
* @since 3.4.0
*
* @return string URL of the origin. Empty string if no origin.
*/
function get_http_origin() {
$origin = '';
if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
$origin = $_SERVER[ 'HTTP_ORIGIN' ];
/**
* Change the origin of an HTTP request.
*
* @since 3.4.0
*
* @param string $origin The original origin for the request.
*/
return apply_filters( 'http_origin', $origin );
}
/**
* Retrieve list of allowed HTTP origins.
*
* @since 3.4.0
*
* @return array Array of origin URLs.
*/
function get_allowed_http_origins() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
// @todo preserve port?
$allowed_origins = array_unique( array(
'http://' . $admin_origin[ 'host' ],
'https://' . $admin_origin[ 'host' ],
'http://' . $home_origin[ 'host' ],
'https://' . $home_origin[ 'host' ],
) );
/**
* Change the origin types allowed for HTTP requests.
*
* @since 3.4.0
*
* @param array $allowed_origins {
* Default allowed HTTP origins.
* @type string Non-secure URL for admin origin.
* @type string Secure URL for admin origin.
* @type string Non-secure URL for home origin.
* @type string Secure URL for home origin.
* }
*/
return apply_filters( 'allowed_http_origins' , $allowed_origins );
}
/**
* Determines if the HTTP origin is an authorized one.
*
* @since 3.4.0
*
* @param null|string $origin Origin URL. If not provided, the value of get_http_origin() is used.
* @return string True if the origin is allowed. False otherwise.
*/
function is_allowed_http_origin( $origin = null ) {
$origin_arg = $origin;
if ( null === $origin )
$origin = get_http_origin();
if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
$origin = '';
/**
* Change the allowed HTTP origin result.
*
* @since 3.4.0
*
* @param string $origin Result of check for allowed origin.
* @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
*/
return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
}
/**
* Send Access-Control-Allow-Origin and related headers if the current request
* is from an allowed origin.
*
* If the request is an OPTIONS request, the script exits with either access
* control headers sent, or a 403 response if the origin is not allowed. For
* other request methods, you will receive a return value.
*
* @since 3.4.0
*
* @return string|false Returns the origin URL if headers are sent. Returns false
* if headers are not sent.
*/
function send_origin_headers() {
$origin = get_http_origin();
if ( is_allowed_http_origin( $origin ) ) {
@header( 'Access-Control-Allow-Origin: ' . $origin );
@header( 'Access-Control-Allow-Credentials: true' );
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
exit;
return $origin;
}
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
status_header( 403 );
exit;
}
return false;
}
/**
* Validate a URL for safe use in the HTTP API.
*
* @since 3.5.2
*
* @param string $url
* @return false|string URL or false on failure.
*/
function wp_http_validate_url( $url ) {
$original_url = $url;
$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) )
return false;
$parsed_url = @parse_url( $url );
if ( ! $parsed_url || empty( $parsed_url['host'] ) )
return false;
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
return false;
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) )
return false;
$parsed_home = @parse_url( get_option( 'home' ) );
$same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
if ( ! $same_host ) {
$host = trim( $parsed_url['host'], '.' );
if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
$ip = $host;
} else {
$ip = gethostbyname( $host );
if ( $ip === $host ) // Error condition for gethostbyname()
$ip = false;
}
if ( $ip ) {
$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0]
|| ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
|| ( 192 === $parts[0] && 168 === $parts[1] )
) {
// If host appears local, reject unless specifically allowed.
/**
* Check if HTTP request is external or not.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 3.6.0
*
* @param bool false Whether HTTP request is external or not.
* @param string $host IP of the requested host.
* @param string $url URL of the requested host.
*/
if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
return false;
}
}
}
if ( empty( $parsed_url['port'] ) )
return $url;
$port = $parsed_url['port'];
if ( 80 === $port || 443 === $port || 8080 === $port )
return $url;
if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port )
return $url;
return false;
}
/**
* Whitelists allowed redirect hosts for safe HTTP requests as well.
*
* Attached to the http_request_host_is_external filter.
*
* @since 3.6.0
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function allowed_http_request_hosts( $is_external, $host ) {
if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
$is_external = true;
return $is_external;
}
/**
* Whitelists any domain in a multisite installation for safe HTTP requests.
*
* Attached to the http_request_host_is_external filter.
*
* @since 3.6.0
*
* @global wpdb $wpdb WordPress database abstraction object.
* @staticvar array $queried
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function ms_allowed_http_request_hosts( $is_external, $host ) {
global $wpdb;
static $queried = array();
if ( $is_external )
return $is_external;
if ( $host === get_current_site()->domain )
return true;
if ( isset( $queried[ $host ] ) )
return $queried[ $host ];
$queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
return $queried[ $host ];
}
/**
* A wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7
*
* PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including
* schemeless and relative url's with :// in the path, this works around those
* limitations providing a standard output on PHP 5.2~5.4+.
*
* Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated
* when URL parsing failed.
*
* @since 4.4.0
*
* @param string $url The URL to parse.
* @return bool|array False on failure; Array of URL components on success;
* See parse_url()'s return values.
*/
function wp_parse_url( $url ) {
$parts = @parse_url( $url );
if ( ! $parts ) {
// < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
// Since we know it's a relative path, prefix with a scheme/host placeholder and try again
if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
return $parts;
}
// Remove the placeholder values
unset( $parts['scheme'], $parts['host'] );
} else {
return $parts;
}
}
// < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
$path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
$parts['host'] = $path_parts[0];
if ( isset( $path_parts[1] ) ) {
$parts['path'] = '/' . $path_parts[1];
} else {
unset( $parts['path'] );
}
}
return $parts;
}

View File

@ -7,29 +7,656 @@
*
* @package WordPress
* @subpackage HTTP
* @since 2.7.0
*/
/** Core HTTP API functionality */
require_once( ABSPATH . WPINC . '/http-functions.php' );
/**
* Returns the initialized WP_Http Object
*
* @since 2.7.0
* @access private
*
* @staticvar WP_Http $http
*
* @return WP_Http HTTP Transport object.
*/
function _wp_http_get_object() {
static $http = null;
/** WP_Http class */
require_once( ABSPATH . WPINC . '/class-http.php' );
if ( is_null( $http ) ) {
$http = new WP_Http();
}
return $http;
}
/** WP_Http_Streams class */
require_once( ABSPATH . WPINC . '/class-wp-http-streams.php' );
/**
* Retrieve the raw response from a safe HTTP request.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_request( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/** WP_Http_Curl transport class */
require_once( ABSPATH . WPINC . '/class-wp-http-curl.php' );
/**
* Retrieve the raw response from a safe HTTP request using the GET method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_get( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/** WP_HTTP_Proxy transport class */
require_once( ABSPATH . WPINC . '/class-wp-http-proxy.php' );
/**
* Retrieve the raw response from a safe HTTP request using the POST method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_post( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/** WP_Http_Cookie class */
require_once( ABSPATH . WPINC . '/class-wp-http-cookie.php' );
/**
* Retrieve the raw response from a safe HTTP request using the HEAD method.
*
* This function is ideal when the HTTP request is being made to an arbitrary
* URL. The URL is validated to avoid redirection and request forgery attacks.
*
* @since 3.6.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_safe_remote_head( $url, $args = array() ) {
$args['reject_unsafe_urls'] = true;
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/** WP_Http_Encoding class */
require_once( ABSPATH . WPINC . '/class-wp-http-encoding.php' );
/**
* Retrieve the raw response from the HTTP request.
*
* The array structure is a little complex:
*
* $res = array(
* 'headers' => array(),
* 'response' => array(
* 'code' => int,
* 'message' => string
* )
* );
*
* All of the headers in $res['headers'] are with the name as the key and the
* value as the value. So to get the User-Agent, you would do the following.
*
* $user_agent = $res['headers']['user-agent'];
*
* The body is the raw response content and can be retrieved from $res['body'].
*
* This function is called first to make the request and there are other API
* functions to abstract out the above convoluted setup.
*
* Request method defaults for helper functions:
* - Default 'GET' for wp_remote_get()
* - Default 'POST' for wp_remote_post()
* - Default 'HEAD' for wp_remote_head()
*
* @since 2.7.0
*
* @see WP_Http::request() For additional information on default arguments.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_request($url, $args = array()) {
$http = _wp_http_get_object();
return $http->request( $url, $args );
}
/** WP_HTTP_Response class */
require_once( ABSPATH . WPINC . '/class-wp-http-response.php' );
/**
* Retrieve the raw response from the HTTP request using the GET method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_get($url, $args = array()) {
$http = _wp_http_get_object();
return $http->get( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request using the POST method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_post($url, $args = array()) {
$http = _wp_http_get_object();
return $http->post( $url, $args );
}
/**
* Retrieve the raw response from the HTTP request using the HEAD method.
*
* @since 2.7.0
*
* @see wp_remote_request() For more information on the response array format.
* @see WP_Http::request() For default arguments information.
*
* @param string $url Site URL to retrieve.
* @param array $args Optional. Request arguments. Default empty array.
* @return WP_Error|array The response or WP_Error on failure.
*/
function wp_remote_head($url, $args = array()) {
$http = _wp_http_get_object();
return $http->head( $url, $args );
}
/**
* Retrieve only the headers from the raw response.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return array The headers of the response. Empty array if incorrect parameter given.
*/
function wp_remote_retrieve_headers( $response ) {
if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
return array();
return $response['headers'];
}
/**
* Retrieve a single header by name from the raw response.
*
* @since 2.7.0
*
* @param array $response
* @param string $header Header name to retrieve value from.
* @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
*/
function wp_remote_retrieve_header( $response, $header ) {
if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
return '';
if ( array_key_exists($header, $response['headers']) )
return $response['headers'][$header];
return '';
}
/**
* Retrieve only the response code from the raw response.
*
* Will return an empty array if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return int|string The response code as an integer. Empty string on incorrect parameter given.
*/
function wp_remote_retrieve_response_code( $response ) {
if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
return '';
return $response['response']['code'];
}
/**
* Retrieve only the response message from the raw response.
*
* Will return an empty array if incorrect parameter value is given.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return string The response message. Empty string on incorrect parameter given.
*/
function wp_remote_retrieve_response_message( $response ) {
if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
return '';
return $response['response']['message'];
}
/**
* Retrieve only the body from the raw response.
*
* @since 2.7.0
*
* @param array $response HTTP response.
* @return string The body of the response. Empty string if no body or incorrect parameter given.
*/
function wp_remote_retrieve_body( $response ) {
if ( is_wp_error($response) || ! isset($response['body']) )
return '';
return $response['body'];
}
/**
* Retrieve only the body from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @return array An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error.
*/
function wp_remote_retrieve_cookies( $response ) {
if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
return array();
}
return $response['cookies'];
}
/**
* Retrieve a single cookie by name from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response.
*/
function wp_remote_retrieve_cookie( $response, $name ) {
$cookies = wp_remote_retrieve_cookies( $response );
if ( empty( $cookies ) ) {
return '';
}
foreach ( $cookies as $cookie ) {
if ( $cookie->name === $name ) {
return $cookie;
}
}
return '';
}
/**
* Retrieve a single cookie's value by name from the raw response.
*
* @since 4.4.0
*
* @param array $response HTTP response.
* @param string $name The name of the cookie to retrieve.
* @return string The value of the cookie. Empty string if the cookie isn't present in the response.
*/
function wp_remote_retrieve_cookie_value( $response, $name ) {
$cookie = wp_remote_retrieve_cookie( $response, $name );
if ( ! is_a( $cookie, 'WP_Http_Cookie' ) ) {
return '';
}
return $cookie->value;
}
/**
* Determines if there is an HTTP Transport that can process this request.
*
* @since 3.2.0
*
* @param array $capabilities Array of capabilities to test or a wp_remote_request() $args array.
* @param string $url Optional. If given, will check if the URL requires SSL and adds
* that requirement to the capabilities array.
*
* @return bool
*/
function wp_http_supports( $capabilities = array(), $url = null ) {
$http = _wp_http_get_object();
$capabilities = wp_parse_args( $capabilities );
$count = count( $capabilities );
// If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
$capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
}
if ( $url && !isset( $capabilities['ssl'] ) ) {
$scheme = parse_url( $url, PHP_URL_SCHEME );
if ( 'https' == $scheme || 'ssl' == $scheme ) {
$capabilities['ssl'] = true;
}
}
return (bool) $http->_get_first_available_transport( $capabilities );
}
/**
* Get the HTTP Origin of the current request.
*
* @since 3.4.0
*
* @return string URL of the origin. Empty string if no origin.
*/
function get_http_origin() {
$origin = '';
if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
$origin = $_SERVER[ 'HTTP_ORIGIN' ];
/**
* Change the origin of an HTTP request.
*
* @since 3.4.0
*
* @param string $origin The original origin for the request.
*/
return apply_filters( 'http_origin', $origin );
}
/**
* Retrieve list of allowed HTTP origins.
*
* @since 3.4.0
*
* @return array Array of origin URLs.
*/
function get_allowed_http_origins() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
// @todo preserve port?
$allowed_origins = array_unique( array(
'http://' . $admin_origin[ 'host' ],
'https://' . $admin_origin[ 'host' ],
'http://' . $home_origin[ 'host' ],
'https://' . $home_origin[ 'host' ],
) );
/**
* Change the origin types allowed for HTTP requests.
*
* @since 3.4.0
*
* @param array $allowed_origins {
* Default allowed HTTP origins.
* @type string Non-secure URL for admin origin.
* @type string Secure URL for admin origin.
* @type string Non-secure URL for home origin.
* @type string Secure URL for home origin.
* }
*/
return apply_filters( 'allowed_http_origins' , $allowed_origins );
}
/**
* Determines if the HTTP origin is an authorized one.
*
* @since 3.4.0
*
* @param null|string $origin Origin URL. If not provided, the value of get_http_origin() is used.
* @return string True if the origin is allowed. False otherwise.
*/
function is_allowed_http_origin( $origin = null ) {
$origin_arg = $origin;
if ( null === $origin )
$origin = get_http_origin();
if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
$origin = '';
/**
* Change the allowed HTTP origin result.
*
* @since 3.4.0
*
* @param string $origin Result of check for allowed origin.
* @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
*/
return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
}
/**
* Send Access-Control-Allow-Origin and related headers if the current request
* is from an allowed origin.
*
* If the request is an OPTIONS request, the script exits with either access
* control headers sent, or a 403 response if the origin is not allowed. For
* other request methods, you will receive a return value.
*
* @since 3.4.0
*
* @return string|false Returns the origin URL if headers are sent. Returns false
* if headers are not sent.
*/
function send_origin_headers() {
$origin = get_http_origin();
if ( is_allowed_http_origin( $origin ) ) {
@header( 'Access-Control-Allow-Origin: ' . $origin );
@header( 'Access-Control-Allow-Credentials: true' );
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
exit;
return $origin;
}
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
status_header( 403 );
exit;
}
return false;
}
/**
* Validate a URL for safe use in the HTTP API.
*
* @since 3.5.2
*
* @param string $url
* @return false|string URL or false on failure.
*/
function wp_http_validate_url( $url ) {
$original_url = $url;
$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) )
return false;
$parsed_url = @parse_url( $url );
if ( ! $parsed_url || empty( $parsed_url['host'] ) )
return false;
if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
return false;
if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) )
return false;
$parsed_home = @parse_url( get_option( 'home' ) );
$same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
if ( ! $same_host ) {
$host = trim( $parsed_url['host'], '.' );
if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
$ip = $host;
} else {
$ip = gethostbyname( $host );
if ( $ip === $host ) // Error condition for gethostbyname()
$ip = false;
}
if ( $ip ) {
$parts = array_map( 'intval', explode( '.', $ip ) );
if ( 127 === $parts[0] || 10 === $parts[0]
|| ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
|| ( 192 === $parts[0] && 168 === $parts[1] )
) {
// If host appears local, reject unless specifically allowed.
/**
* Check if HTTP request is external or not.
*
* Allows to change and allow external requests for the HTTP request.
*
* @since 3.6.0
*
* @param bool false Whether HTTP request is external or not.
* @param string $host IP of the requested host.
* @param string $url URL of the requested host.
*/
if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
return false;
}
}
}
if ( empty( $parsed_url['port'] ) )
return $url;
$port = $parsed_url['port'];
if ( 80 === $port || 443 === $port || 8080 === $port )
return $url;
if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port )
return $url;
return false;
}
/**
* Whitelists allowed redirect hosts for safe HTTP requests as well.
*
* Attached to the http_request_host_is_external filter.
*
* @since 3.6.0
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function allowed_http_request_hosts( $is_external, $host ) {
if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
$is_external = true;
return $is_external;
}
/**
* Whitelists any domain in a multisite installation for safe HTTP requests.
*
* Attached to the http_request_host_is_external filter.
*
* @since 3.6.0
*
* @global wpdb $wpdb WordPress database abstraction object.
* @staticvar array $queried
*
* @param bool $is_external
* @param string $host
* @return bool
*/
function ms_allowed_http_request_hosts( $is_external, $host ) {
global $wpdb;
static $queried = array();
if ( $is_external )
return $is_external;
if ( $host === get_current_site()->domain )
return true;
if ( isset( $queried[ $host ] ) )
return $queried[ $host ];
$queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
return $queried[ $host ];
}
/**
* A wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7
*
* PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including
* schemeless and relative url's with :// in the path, this works around those
* limitations providing a standard output on PHP 5.2~5.4+.
*
* Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated
* when URL parsing failed.
*
* @since 4.4.0
*
* @param string $url The URL to parse.
* @return bool|array False on failure; Array of URL components on success;
* See parse_url()'s return values.
*/
function wp_parse_url( $url ) {
$parts = @parse_url( $url );
if ( ! $parts ) {
// < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path
if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) {
// Since we know it's a relative path, prefix with a scheme/host placeholder and try again
if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url ) ) {
return $parts;
}
// Remove the placeholder values
unset( $parts['scheme'], $parts['host'] );
} else {
return $parts;
}
}
// < PHP 5.4.7 compat, doesn't detect schemeless URL's host field
if ( '//' == substr( $url, 0, 2 ) && ! isset( $parts['host'] ) ) {
$path_parts = explode( '/', substr( $parts['path'], 2 ), 2 );
$parts['host'] = $path_parts[0];
if ( isset( $path_parts[1] ) ) {
$parts['path'] = '/' . $path_parts[1];
} else {
unset( $parts['path'] );
}
}
return $parts;
}

View File

@ -1,968 +0,0 @@
<?php
/**
* Meta API: Top-level metadata functionality
*
* Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
* for an object is a represented by a simple key-value pair. Objects may contain multiple
* metadata entries that share the same key and differ only in their value.
*
* @package WordPress
* @subpackage Meta
* @since 4.4.0
*/
/**
* Add metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Optional, default is false.
* Whether the specified metadata key should be unique for the object.
* If true, and the object already has a value for the specified metadata key,
* no change will be made.
* @return int|false The meta ID on success, false on failure.
*/
function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$meta_value = wp_unslash($meta_value);
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
/**
* Filter whether to add metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow adding metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $unique Whether the specified meta key should be unique
* for the object. Optional. Default false.
*/
$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
if ( null !== $check )
return $check;
if ( $unique && $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
$meta_key, $object_id ) ) )
return false;
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
/**
* Fires immediately before meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 3.1.0
*
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
$result = $wpdb->insert( $table, array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value
) );
if ( ! $result )
return false;
$mid = (int) $wpdb->insert_id;
wp_cache_delete($object_id, $meta_type . '_meta');
/**
* Fires immediately after meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $mid The meta ID after successful update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
return $mid;
}
/**
* Update metadata for the specified object. If no value already exists for the specified object
* ID and metadata key, the metadata will be added.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing metadata entries with
* the specified value. Otherwise, update all entries.
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
*/
function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$passed_value = $meta_value;
$meta_value = wp_unslash($meta_value);
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
/**
* Filter whether to update metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing
* metadata entries with the specified value.
* Otherwise, update all entries.
*/
$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
if ( null !== $check )
return (bool) $check;
// Compare existing value to new value if no prev value given and the key exists only once.
if ( empty($prev_value) ) {
$old_value = get_metadata($meta_type, $object_id, $meta_key);
if ( count($old_value) == 1 ) {
if ( $old_value[0] === $meta_value )
return false;
}
}
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
if ( empty( $meta_ids ) ) {
return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$data = compact( 'meta_value' );
$where = array( $column => $object_id, 'meta_key' => $meta_key );
if ( !empty( $prev_value ) ) {
$prev_value = maybe_serialize($prev_value);
$where['meta_value'] = $prev_value;
}
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of the metadata entry to update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
}
if ( 'post' == $meta_type ) {
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of metadata entry to update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
$result = $wpdb->update( $table, $data, $where );
if ( ! $result )
return false;
wp_cache_delete($object_id, $meta_type . '_meta');
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
}
if ( 'post' == $meta_type ) {
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
return true;
}
/**
* Delete metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
* metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
* Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,
* it is not possible to pass an empty string to delete those entries with an empty string
* for a value.)
* @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
* ignoring the specified object_id. Otherwise, only delete matching metadata entries for
* the specified object_id.
* @return bool True on successful delete, false on failure.
*/
function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id && ! $delete_all ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$type_column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$meta_value = wp_unslash($meta_value);
/**
* Filter whether to delete metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $delete_all Whether to delete the matching metadata entries
* for all objects, ignoring the specified $object_id.
* Default false.
*/
$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
if ( null !== $check )
return (bool) $check;
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
if ( !$delete_all )
$query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value )
$query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );
$meta_ids = $wpdb->get_col( $query );
if ( !count( $meta_ids ) )
return false;
if ( $delete_all )
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
/**
* Fires immediately before deleting metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 3.1.0
*
* @param array $meta_ids An array of metadata entry IDs to delete.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately before deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of post metadata entry IDs to delete.
*/
do_action( 'delete_postmeta', $meta_ids );
}
$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
$count = $wpdb->query($query);
if ( !$count )
return false;
if ( $delete_all ) {
foreach ( (array) $object_ids as $o_id ) {
wp_cache_delete($o_id, $meta_type . '_meta');
}
} else {
wp_cache_delete($object_id, $meta_type . '_meta');
}
/**
* Fires immediately after deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted metadata entry IDs.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately after deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted post metadata entry IDs.
*/
do_action( 'deleted_postmeta', $meta_ids );
}
return true;
}
/**
* Retrieve metadata for the specified object.
*
* @since 2.9.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object.
* @param bool $single Optional, default is false.
* If true, return only the first value of the specified meta_key.
* This parameter has no effect if meta_key is not specified.
* @return mixed Single metadata value, or array of values
*/
function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/**
* Filter whether to retrieve metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|array|string $value The value get_metadata() should return - a single metadata value,
* or an array of values.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param bool $single Whether to return only the first value of the specified $meta_key.
*/
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
if ( null !== $check ) {
if ( $single && is_array( $check ) )
return $check[0];
else
return $check;
}
$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
if ( !$meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[$object_id];
}
if ( ! $meta_key ) {
return $meta_cache;
}
if ( isset($meta_cache[$meta_key]) ) {
if ( $single )
return maybe_unserialize( $meta_cache[$meta_key][0] );
else
return array_map('maybe_unserialize', $meta_cache[$meta_key]);
}
if ($single)
return '';
else
return array();
}
/**
* Determine if a meta key is set for a given object
*
* @since 3.3.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key.
* @return bool True of the key is set, false if not.
*/
function metadata_exists( $meta_type, $object_id, $meta_key ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/** This filter is documented in wp-includes/meta-functions.php */
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
if ( null !== $check )
return (bool) $check;
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( !$meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[$object_id];
}
if ( isset( $meta_cache[ $meta_key ] ) )
return true;
return false;
}
/**
* Get meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return object|false Meta object or false.
*/
function get_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
$meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
if ( empty( $meta ) )
return false;
if ( isset( $meta->meta_value ) )
$meta->meta_value = maybe_unserialize( $meta->meta_value );
return $meta;
}
/**
* Update meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $meta_id ID for a specific meta row
* @param string $meta_value Metadata value
* @param string $meta_key Optional, you can provide a meta key to update it
* @return bool True on successful update, false on failure.
*/
function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$original_key = $meta->meta_key;
$object_id = $meta->{$column};
// If a new meta_key (last parameter) was specified, change the meta key,
// otherwise use the original key in the update statement.
if ( false === $meta_key ) {
$meta_key = $original_key;
} elseif ( ! is_string( $meta_key ) ) {
return false;
}
// Sanitize the meta
$_meta_value = $meta_value;
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
$meta_value = maybe_serialize( $meta_value );
// Format the data query arguments.
$data = array(
'meta_key' => $meta_key,
'meta_value' => $meta_value
);
// Format the where query arguments.
$where = array();
$where[$id_column] = $meta_id;
/** This action is documented in wp-includes/meta-functions.php */
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta-functions.php */
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
// Run the update query, all fields in $data are %s, $where is a %d.
$result = $wpdb->update( $table, $data, $where, '%s', '%d' );
if ( ! $result )
return false;
// Clear the caches.
wp_cache_delete($object_id, $meta_type . '_meta');
/** This action is documented in wp-includes/meta-functions.php */
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta-functions.php */
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
return true;
}
// And if the meta was not found.
return false;
}
/**
* Delete meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return bool True on successful delete, false on failure.
*/
function delete_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
// object and id columns
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$object_id = $meta->{$column};
/** This action is documented in wp-includes/meta-functions.php */
do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately before deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_id ID of the metadata entry to delete.
*/
do_action( "delete_{$meta_type}meta", $meta_id );
}
// Run the query, will return true if deleted, false otherwise
$result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
// Clear the caches.
wp_cache_delete($object_id, $meta_type . '_meta');
/** This action is documented in wp-includes/meta-functions.php */
do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately after deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_ids Deleted metadata entry ID.
*/
do_action( "deleted_{$meta_type}meta", $meta_id );
}
return $result;
}
// Meta id was not found.
return false;
}
/**
* Update the metadata cache for the specified objects.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
* @return array|false Metadata cache for the specified objects, or false on failure.
*/
function update_meta_cache($meta_type, $object_ids) {
global $wpdb;
if ( ! $meta_type || ! $object_ids ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
if ( !is_array($object_ids) ) {
$object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
$object_ids = explode(',', $object_ids);
}
$object_ids = array_map('intval', $object_ids);
$cache_key = $meta_type . '_meta';
$ids = array();
$cache = array();
foreach ( $object_ids as $id ) {
$cached_object = wp_cache_get( $id, $cache_key );
if ( false === $cached_object )
$ids[] = $id;
else
$cache[$id] = $cached_object;
}
if ( empty( $ids ) )
return $cache;
// Get meta info
$id_list = join( ',', $ids );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
$meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
if ( !empty($meta_list) ) {
foreach ( $meta_list as $metarow) {
$mpid = intval($metarow[$column]);
$mkey = $metarow['meta_key'];
$mval = $metarow['meta_value'];
// Force subkeys to be array type:
if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
$cache[$mpid] = array();
if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
$cache[$mpid][$mkey] = array();
// Add a value to the current pid/key:
$cache[$mpid][$mkey][] = $mval;
}
}
foreach ( $ids as $id ) {
if ( ! isset($cache[$id]) )
$cache[$id] = array();
wp_cache_add( $id, $cache[$id], $cache_key );
}
return $cache;
}
/**
* Given a meta query, generates SQL clauses to be appended to a main query.
*
* @since 3.2.0
*
* @see WP_Meta_Query
*
* @param array $meta_query A meta query.
* @param string $type Type of meta.
* @param string $primary_table Primary database table name.
* @param string $primary_id_column Primary ID column name.
* @param object $context Optional. The main query object
* @return array Associative array of `JOIN` and `WHERE` SQL.
*/
function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
$meta_query_obj = new WP_Meta_Query( $meta_query );
return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
}
/**
* Retrieve the name of the metadata table for the specified object type.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
* @return string|false Metadata table name, or false if no metadata table exists
*/
function _get_meta_table($type) {
global $wpdb;
$table_name = $type . 'meta';
if ( empty($wpdb->$table_name) )
return false;
return $wpdb->$table_name;
}
/**
* Determine whether a meta key is protected.
*
* @since 3.1.3
*
* @param string $meta_key Meta key
* @param string|null $meta_type
* @return bool True if the key is protected, false otherwise.
*/
function is_protected_meta( $meta_key, $meta_type = null ) {
$protected = ( '_' == $meta_key[0] );
/**
* Filter whether a meta key is protected.
*
* @since 3.2.0
*
* @param bool $protected Whether the key is protected. Default false.
* @param string $meta_key Meta key.
* @param string $meta_type Meta type.
*/
return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}
/**
* Sanitize meta value.
*
* @since 3.1.3
*
* @param string $meta_key Meta key
* @param mixed $meta_value Meta value to sanitize
* @param string $meta_type Type of meta
* @return mixed Sanitized $meta_value
*/
function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
/**
* Filter the sanitization of a specific meta key of a specific meta type.
*
* The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
* refer to the metadata object type (comment, post, or user) and the meta
* key value,
* respectively.
*
* @since 3.3.0
*
* @param mixed $meta_value Meta value to sanitize.
* @param string $meta_key Meta key.
* @param string $meta_type Meta type.
*/
return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
}
/**
* Register meta key
*
* @since 3.3.0
*
* @param string $meta_type Type of meta
* @param string $meta_key Meta key
* @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
* @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
*/
function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
if ( is_callable( $sanitize_callback ) )
add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
if ( empty( $auth_callback ) ) {
if ( is_protected_meta( $meta_key, $meta_type ) )
$auth_callback = '__return_false';
else
$auth_callback = '__return_true';
}
if ( is_callable( $auth_callback ) )
add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
}

View File

@ -8,11 +8,960 @@
*
* @package WordPress
* @subpackage Meta
* @since 2.9.0
*/
/** Core metdata functionality */
require_once( ABSPATH . WPINC . '/meta-functions.php' );
/**
* Add metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $unique Optional, default is false.
* Whether the specified metadata key should be unique for the object.
* If true, and the object already has a value for the specified metadata key,
* no change will be made.
* @return int|false The meta ID on success, false on failure.
*/
function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
global $wpdb;
/** WP_Meta_Query class */
require_once( ABSPATH . WPINC . '/class-wp-meta-query.php' );
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$meta_value = wp_unslash($meta_value);
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
/**
* Filter whether to add metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow adding metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $unique Whether the specified meta key should be unique
* for the object. Optional. Default false.
*/
$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
if ( null !== $check )
return $check;
if ( $unique && $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
$meta_key, $object_id ) ) )
return false;
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
/**
* Fires immediately before meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 3.1.0
*
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
$result = $wpdb->insert( $table, array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value
) );
if ( ! $result )
return false;
$mid = (int) $wpdb->insert_id;
wp_cache_delete($object_id, $meta_type . '_meta');
/**
* Fires immediately after meta of a specific type is added.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $mid The meta ID after successful update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
return $mid;
}
/**
* Update metadata for the specified object. If no value already exists for the specified object
* ID and metadata key, the metadata will be added.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing metadata entries with
* the specified value. Otherwise, update all entries.
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
*/
function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$passed_value = $meta_value;
$meta_value = wp_unslash($meta_value);
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
/**
* Filter whether to update metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $check Whether to allow updating metadata for the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param mixed $prev_value Optional. If specified, only update existing
* metadata entries with the specified value.
* Otherwise, update all entries.
*/
$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
if ( null !== $check )
return (bool) $check;
// Compare existing value to new value if no prev value given and the key exists only once.
if ( empty($prev_value) ) {
$old_value = get_metadata($meta_type, $object_id, $meta_key);
if ( count($old_value) == 1 ) {
if ( $old_value[0] === $meta_value )
return false;
}
}
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
if ( empty( $meta_ids ) ) {
return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
}
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$data = compact( 'meta_value' );
$where = array( $column => $object_id, 'meta_key' => $meta_key );
if ( !empty( $prev_value ) ) {
$prev_value = maybe_serialize($prev_value);
$where['meta_value'] = $prev_value;
}
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of the metadata entry to update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
}
if ( 'post' == $meta_type ) {
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of metadata entry to update.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
$result = $wpdb->update( $table, $data, $where );
if ( ! $result )
return false;
wp_cache_delete($object_id, $meta_type . '_meta');
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
}
if ( 'post' == $meta_type ) {
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating a post's metadata.
*
* @since 2.9.0
*
* @param int $meta_id ID of updated metadata entry.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
}
return true;
}
/**
* Delete metadata for the specified object.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key
* @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
* metadata entries with this value. Otherwise, delete all entries with the specified meta_key.
* Pass `null, `false`, or an empty string to skip this check. (For backward compatibility,
* it is not possible to pass an empty string to delete those entries with an empty string
* for a value.)
* @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects,
* ignoring the specified object_id. Otherwise, only delete matching metadata entries for
* the specified object_id.
* @return bool True on successful delete, false on failure.
*/
function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
global $wpdb;
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id && ! $delete_all ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$type_column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// expected_slashed ($meta_key)
$meta_key = wp_unslash($meta_key);
$meta_value = wp_unslash($meta_value);
/**
* Filter whether to delete metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|bool $delete Whether to allow metadata deletion of the given type.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
* @param bool $delete_all Whether to delete the matching metadata entries
* for all objects, ignoring the specified $object_id.
* Default false.
*/
$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
if ( null !== $check )
return (bool) $check;
$_meta_value = $meta_value;
$meta_value = maybe_serialize( $meta_value );
$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
if ( !$delete_all )
$query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value )
$query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );
$meta_ids = $wpdb->get_col( $query );
if ( !count( $meta_ids ) )
return false;
if ( $delete_all )
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
/**
* Fires immediately before deleting metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 3.1.0
*
* @param array $meta_ids An array of metadata entry IDs to delete.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately before deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of post metadata entry IDs to delete.
*/
do_action( 'delete_postmeta', $meta_ids );
}
$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
$count = $wpdb->query($query);
if ( !$count )
return false;
if ( $delete_all ) {
foreach ( (array) $object_ids as $o_id ) {
wp_cache_delete($o_id, $meta_type . '_meta');
}
} else {
wp_cache_delete($object_id, $meta_type . '_meta');
}
/**
* Fires immediately after deleting metadata of a specific type.
*
* The dynamic portion of the hook name, `$meta_type`, refers to the meta
* object type (comment, post, or user).
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted metadata entry IDs.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param mixed $meta_value Meta value.
*/
do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately after deleting metadata for a post.
*
* @since 2.9.0
*
* @param array $meta_ids An array of deleted post metadata entry IDs.
*/
do_action( 'deleted_postmeta', $meta_ids );
}
return true;
}
/**
* Retrieve metadata for the specified object.
*
* @since 2.9.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
* the specified object.
* @param bool $single Optional, default is false.
* If true, return only the first value of the specified meta_key.
* This parameter has no effect if meta_key is not specified.
* @return mixed Single metadata value, or array of values
*/
function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/**
* Filter whether to retrieve metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (comment, post, or user). Returning a non-null value
* will effectively short-circuit the function.
*
* @since 3.1.0
*
* @param null|array|string $value The value get_metadata() should return - a single metadata value,
* or an array of values.
* @param int $object_id Object ID.
* @param string $meta_key Meta key.
* @param bool $single Whether to return only the first value of the specified $meta_key.
*/
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
if ( null !== $check ) {
if ( $single && is_array( $check ) )
return $check[0];
else
return $check;
}
$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
if ( !$meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[$object_id];
}
if ( ! $meta_key ) {
return $meta_cache;
}
if ( isset($meta_cache[$meta_key]) ) {
if ( $single )
return maybe_unserialize( $meta_cache[$meta_key][0] );
else
return array_map('maybe_unserialize', $meta_cache[$meta_key]);
}
if ($single)
return '';
else
return array();
}
/**
* Determine if a meta key is set for a given object
*
* @since 3.3.0
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $object_id ID of the object metadata is for
* @param string $meta_key Metadata key.
* @return bool True of the key is set, false if not.
*/
function metadata_exists( $meta_type, $object_id, $meta_key ) {
if ( ! $meta_type || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
/** This filter is documented in wp-includes/meta-functions.php */
$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
if ( null !== $check )
return (bool) $check;
$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
if ( !$meta_cache ) {
$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
$meta_cache = $meta_cache[$object_id];
}
if ( isset( $meta_cache[ $meta_key ] ) )
return true;
return false;
}
/**
* Get meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return object|false Meta object or false.
*/
function get_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
$meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
if ( empty( $meta ) )
return false;
if ( isset( $meta->meta_value ) )
$meta->meta_value = maybe_unserialize( $meta->meta_value );
return $meta;
}
/**
* Update meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int $meta_id ID for a specific meta row
* @param string $meta_value Metadata value
* @param string $meta_key Optional, you can provide a meta key to update it
* @return bool True on successful update, false on failure.
*/
function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$original_key = $meta->meta_key;
$object_id = $meta->{$column};
// If a new meta_key (last parameter) was specified, change the meta key,
// otherwise use the original key in the update statement.
if ( false === $meta_key ) {
$meta_key = $original_key;
} elseif ( ! is_string( $meta_key ) ) {
return false;
}
// Sanitize the meta
$_meta_value = $meta_value;
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
$meta_value = maybe_serialize( $meta_value );
// Format the data query arguments.
$data = array(
'meta_key' => $meta_key,
'meta_value' => $meta_value
);
// Format the where query arguments.
$where = array();
$where[$id_column] = $meta_id;
/** This action is documented in wp-includes/meta-functions.php */
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta-functions.php */
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
// Run the update query, all fields in $data are %s, $where is a %d.
$result = $wpdb->update( $table, $data, $where, '%s', '%d' );
if ( ! $result )
return false;
// Clear the caches.
wp_cache_delete($object_id, $meta_type . '_meta');
/** This action is documented in wp-includes/meta-functions.php */
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
if ( 'post' == $meta_type ) {
/** This action is documented in wp-includes/meta-functions.php */
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
}
return true;
}
// And if the meta was not found.
return false;
}
/**
* Delete meta data by meta ID
*
* @since 3.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
* @param int $meta_id ID for a specific meta row
* @return bool True on successful delete, false on failure.
*/
function delete_metadata_by_mid( $meta_type, $meta_id ) {
global $wpdb;
// Make sure everything is valid.
if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
return false;
}
$meta_id = absint( $meta_id );
if ( ! $meta_id ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
// object and id columns
$column = sanitize_key($meta_type . '_id');
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
// Fetch the meta and go on if it's found.
if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
$object_id = $meta->{$column};
/** This action is documented in wp-includes/meta-functions.php */
do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately before deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_id ID of the metadata entry to delete.
*/
do_action( "delete_{$meta_type}meta", $meta_id );
}
// Run the query, will return true if deleted, false otherwise
$result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
// Clear the caches.
wp_cache_delete($object_id, $meta_type . '_meta');
/** This action is documented in wp-includes/meta-functions.php */
do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately after deleting post or comment metadata of a specific type.
*
* The dynamic portion of the hook, `$meta_type`, refers to the meta
* object type (post or comment).
*
* @since 3.4.0
*
* @param int $meta_ids Deleted metadata entry ID.
*/
do_action( "deleted_{$meta_type}meta", $meta_id );
}
return $result;
}
// Meta id was not found.
return false;
}
/**
* Update the metadata cache for the specified objects.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
* @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
* @return array|false Metadata cache for the specified objects, or false on failure.
*/
function update_meta_cache($meta_type, $object_ids) {
global $wpdb;
if ( ! $meta_type || ! $object_ids ) {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key($meta_type . '_id');
if ( !is_array($object_ids) ) {
$object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
$object_ids = explode(',', $object_ids);
}
$object_ids = array_map('intval', $object_ids);
$cache_key = $meta_type . '_meta';
$ids = array();
$cache = array();
foreach ( $object_ids as $id ) {
$cached_object = wp_cache_get( $id, $cache_key );
if ( false === $cached_object )
$ids[] = $id;
else
$cache[$id] = $cached_object;
}
if ( empty( $ids ) )
return $cache;
// Get meta info
$id_list = join( ',', $ids );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
$meta_list = $wpdb->get_results( "SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list) ORDER BY $id_column ASC", ARRAY_A );
if ( !empty($meta_list) ) {
foreach ( $meta_list as $metarow) {
$mpid = intval($metarow[$column]);
$mkey = $metarow['meta_key'];
$mval = $metarow['meta_value'];
// Force subkeys to be array type:
if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
$cache[$mpid] = array();
if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
$cache[$mpid][$mkey] = array();
// Add a value to the current pid/key:
$cache[$mpid][$mkey][] = $mval;
}
}
foreach ( $ids as $id ) {
if ( ! isset($cache[$id]) )
$cache[$id] = array();
wp_cache_add( $id, $cache[$id], $cache_key );
}
return $cache;
}
/**
* Given a meta query, generates SQL clauses to be appended to a main query.
*
* @since 3.2.0
*
* @see WP_Meta_Query
*
* @param array $meta_query A meta query.
* @param string $type Type of meta.
* @param string $primary_table Primary database table name.
* @param string $primary_id_column Primary ID column name.
* @param object $context Optional. The main query object
* @return array Associative array of `JOIN` and `WHERE` SQL.
*/
function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
$meta_query_obj = new WP_Meta_Query( $meta_query );
return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
}
/**
* Retrieve the name of the metadata table for the specified object type.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
* @return string|false Metadata table name, or false if no metadata table exists
*/
function _get_meta_table($type) {
global $wpdb;
$table_name = $type . 'meta';
if ( empty($wpdb->$table_name) )
return false;
return $wpdb->$table_name;
}
/**
* Determine whether a meta key is protected.
*
* @since 3.1.3
*
* @param string $meta_key Meta key
* @param string|null $meta_type
* @return bool True if the key is protected, false otherwise.
*/
function is_protected_meta( $meta_key, $meta_type = null ) {
$protected = ( '_' == $meta_key[0] );
/**
* Filter whether a meta key is protected.
*
* @since 3.2.0
*
* @param bool $protected Whether the key is protected. Default false.
* @param string $meta_key Meta key.
* @param string $meta_type Meta type.
*/
return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}
/**
* Sanitize meta value.
*
* @since 3.1.3
*
* @param string $meta_key Meta key
* @param mixed $meta_value Meta value to sanitize
* @param string $meta_type Type of meta
* @return mixed Sanitized $meta_value
*/
function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
/**
* Filter the sanitization of a specific meta key of a specific meta type.
*
* The dynamic portions of the hook name, `$meta_type`, and `$meta_key`,
* refer to the metadata object type (comment, post, or user) and the meta
* key value,
* respectively.
*
* @since 3.3.0
*
* @param mixed $meta_value Meta value to sanitize.
* @param string $meta_key Meta key.
* @param string $meta_type Meta type.
*/
return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
}
/**
* Register meta key
*
* @since 3.3.0
*
* @param string $meta_type Type of meta
* @param string $meta_key Meta key
* @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
* @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
*/
function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
if ( is_callable( $sanitize_callback ) )
add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
if ( empty( $auth_callback ) ) {
if ( is_protected_meta( $meta_key, $meta_type ) )
$auth_callback = '__return_false';
else
$auth_callback = '__return_true';
}
if ( is_callable( $auth_callback ) )
add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
*
* @package WordPress
* @subpackage REST_API
* @since 4.4.0
*/
/**
@ -13,14 +14,637 @@
*/
define( 'REST_API_VERSION', '2.0' );
/** WP_REST_Server class */
require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
/**
* Registers a REST API route.
*
* @since 4.4.0
*
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*
* @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
* @param string $route The base URL for route you are adding.
* @param array $args Optional. Either an array of options for the endpoint, or an array of arrays for
* multiple methods. Default empty array.
* @param bool $override Optional. If the route already exists, should we override it? True overrides,
* false merges (with newer overriding if duplicate keys exist). Default false.
* @return bool True on success, false on error.
*/
function register_rest_route( $namespace, $route, $args = array(), $override = false ) {
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
/** WP_REST_Response class */
require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
if ( empty( $namespace ) ) {
/*
* Non-namespaced routes are not allowed, with the exception of the main
* and namespace indexes. If you really need to register a
* non-namespaced route, call `WP_REST_Server::register_route` directly.
*/
_doing_it_wrong( 'register_rest_route', 'Routes must be namespaced with plugin or theme name and version.', '4.4.0' );
return false;
} else if ( empty( $route ) ) {
_doing_it_wrong( 'register_rest_route', 'Route must be specified.', '4.4.0' );
return false;
}
/** WP_REST_Request class */
require_once( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
if ( isset( $args['callback'] ) ) {
// Upgrade a single set to multiple.
$args = array( $args );
}
/** REST functions */
require_once( ABSPATH . WPINC . '/rest-api/rest-functions.php' );
$defaults = array(
'methods' => 'GET',
'callback' => null,
'args' => array(),
);
foreach ( $args as $key => &$arg_group ) {
if ( ! is_numeric( $arg_group ) ) {
// Route option, skip here.
continue;
}
$arg_group = array_merge( $defaults, $arg_group );
}
$full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
$wp_rest_server->register_route( $namespace, $full_route, $args, $override );
return true;
}
/**
* Registers rewrite rules for the API.
*
* @since 4.4.0
*
* @see rest_api_register_rewrites()
* @global WP $wp Current WordPress environment instance.
*/
function rest_api_init() {
rest_api_register_rewrites();
global $wp;
$wp->add_query_var( 'rest_route' );
}
/**
* Adds REST rewrite rules.
*
* @since 4.4.0
*
* @see add_rewrite_rule()
*/
function rest_api_register_rewrites() {
add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
}
/**
* Registers the default REST API filters.
*
* Attached to the {@see 'rest_api_init'} action
* to make testing and disabling these filters easier.
*
* @since 4.4.0
*/
function rest_api_default_filters() {
// Deprecated reporting.
add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
add_filter( 'deprecated_function_trigger_error', '__return_false' );
add_action( 'deprecated_argument_run', 'rest_handle_deprecated_argument', 10, 3 );
add_filter( 'deprecated_argument_trigger_error', '__return_false' );
// Default serving.
add_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
}
/**
* Loads the REST API.
*
* @since 4.4.0
*
* @global WP $wp Current WordPress environment instance.
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*/
function rest_api_loaded() {
if ( empty( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
return;
}
/**
* Whether this is a REST Request.
*
* @since 4.4.0
* @var bool
*/
define( 'REST_REQUEST', true );
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
/**
* Filter the REST Server Class.
*
* This filter allows you to adjust the server class used by the API, using a
* different class to handle requests.
*
* @since 4.4.0
*
* @param string $class_name The name of the server class. Default 'WP_REST_Server'.
*/
$wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
$wp_rest_server = new $wp_rest_server_class;
/**
* Fires when preparing to serve an API request.
*
* Endpoint objects should be created and register their hooks on this action rather
* than another action to ensure they're only loaded when needed.
*
* @since 4.4.0
*
* @param WP_REST_Server $wp_rest_server Server object.
*/
do_action( 'rest_api_init', $wp_rest_server );
// Fire off the request.
$wp_rest_server->serve_request( $GLOBALS['wp']->query_vars['rest_route'] );
// We're done.
die();
}
/**
* Retrieves the URL prefix for any API resource.
*
* @since 4.4.0
*
* @return string Prefix.
*/
function rest_get_url_prefix() {
/**
* Filter the REST URL prefix.
*
* @since 4.4.0
*
* @param string $prefix URL prefix. Default 'wp-json'.
*/
return apply_filters( 'rest_url_prefix', 'wp-json' );
}
/**
* Retrieves the URL to a REST endpoint on a site.
*
* Note: The returned URL is NOT escaped.
*
* @since 4.4.0
*
* @todo Check if this is even necessary
*
* @param int $blog_id Optional. Blog ID. Default of null returns URL for current blog.
* @param string $path Optional. REST route. Default '/'.
* @param string $scheme Optional. Sanitization scheme. Default 'rest'.
* @return string Full URL to the endpoint.
*/
function get_rest_url( $blog_id = null, $path = '/', $scheme = 'rest' ) {
if ( empty( $path ) ) {
$path = '/';
}
if ( is_multisite() && get_blog_option( $blog_id, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) {
$url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
$url .= '/' . ltrim( $path, '/' );
} else {
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
$path = '/' . ltrim( $path, '/' );
$url = add_query_arg( 'rest_route', $path, $url );
}
if ( is_ssl() ) {
// If the current host is the same as the REST URL host, force the REST URL scheme to HTTPS.
if ( $_SERVER['SERVER_NAME'] === parse_url( get_home_url( $blog_id ), PHP_URL_HOST ) ) {
$url = set_url_scheme( $url, 'https' );
}
}
/**
* Filter the REST URL.
*
* Use this filter to adjust the url returned by the `get_rest_url` function.
*
* @since 4.4.0
*
* @param string $url REST URL.
* @param string $path REST route.
* @param int $blog_id Blog ID.
* @param string $scheme Sanitization scheme.
*/
return apply_filters( 'rest_url', $url, $path, $blog_id, $scheme );
}
/**
* Retrieves the URL to a REST endpoint.
*
* Note: The returned URL is NOT escaped.
*
* @since 4.4.0
*
* @param string $path Optional. REST route. Default empty.
* @param string $scheme Optional. Sanitization scheme. Default 'json'.
* @return string Full URL to the endpoint.
*/
function rest_url( $path = '', $scheme = 'json' ) {
return get_rest_url( null, $path, $scheme );
}
/**
* Do a REST request.
*
* Used primarily to route internal requests through WP_REST_Server.
*
* @since 4.4.0
*
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*
* @param WP_REST_Request|string $request Request.
* @return WP_REST_Response REST response.
*/
function rest_do_request( $request ) {
global $wp_rest_server;
$request = rest_ensure_request( $request );
return $wp_rest_server->dispatch( $request );
}
/**
* Ensures request arguments are a request object (for consistency).
*
* @since 4.4.0
*
* @param array|WP_REST_Request $request Request to check.
* @return WP_REST_Request REST request instance.
*/
function rest_ensure_request( $request ) {
if ( $request instanceof WP_REST_Request ) {
return $request;
}
return new WP_REST_Request( 'GET', '', $request );
}
/**
* Ensures a REST response is a response object (for consistency).
*
* This implements WP_HTTP_Response, allowing usage of `set_status`/`header`/etc
* without needing to double-check the object. Will also allow WP_Error to indicate error
* responses, so users should immediately check for this value.
*
* @since 4.4.0
*
* @param WP_Error|WP_HTTP_Response|mixed $response Response to check.
* @return mixed WP_Error if response generated an error, WP_HTTP_Response if response
* is a already an instance, otherwise returns a new WP_REST_Response instance.
*/
function rest_ensure_response( $response ) {
if ( is_wp_error( $response ) ) {
return $response;
}
if ( $response instanceof WP_HTTP_Response ) {
return $response;
}
return new WP_REST_Response( $response );
}
/**
* Handles _deprecated_function() errors.
*
* @since 4.4.0
*
* @param string $function Function name.
* @param string $replacement Replacement function name.
* @param string $version Version.
*/
function rest_handle_deprecated_function( $function, $replacement, $version ) {
if ( ! empty( $replacement ) ) {
/* translators: 1: function name, 2: WordPress version number, 3: new function name */
$string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function, $version, $replacement );
} else {
/* translators: 1: function name, 2: WordPress version number */
$string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
}
header( sprintf( 'X-WP-DeprecatedFunction: %s', $string ) );
}
/**
* Handles _deprecated_argument() errors.
*
* @since 4.4.0
*
* @param string $function Function name.
* @param string $replacement Replacement function name.
* @param string $version Version.
*/
function rest_handle_deprecated_argument( $function, $replacement, $version ) {
if ( ! empty( $replacement ) ) {
/* translators: 1: function name, 2: WordPress version number, 3: new argument name */
$string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function, $version, $replacement );
} else {
/* translators: 1: function name, 2: WordPress version number */
$string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
}
header( sprintf( 'X-WP-DeprecatedParam: %s', $string ) );
}
/**
* Sends Cross-Origin Resource Sharing headers with API requests.
*
* @since 4.4.0
*
* @param mixed $value Response data.
* @return mixed Response data.
*/
function rest_send_cors_headers( $value ) {
$origin = get_http_origin();
if ( $origin ) {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
header( 'Access-Control-Allow-Credentials: true' );
}
return $value;
}
/**
* Handles OPTIONS requests for the server.
*
* This is handled outside of the server code, as it doesn't obey normal route
* mapping.
*
* @since 4.4.0
*
* @param mixed $response Current response, either response or `null` to indicate pass-through.
* @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request The request that was used to make current response.
* @return WP_REST_Response Modified response, either response or `null` to indicate pass-through.
*/
function rest_handle_options_request( $response, $handler, $request ) {
if ( ! empty( $response ) || $request->get_method() !== 'OPTIONS' ) {
return $response;
}
$response = new WP_REST_Response();
$data = array();
$accept = array();
foreach ( $handler->get_routes() as $route => $endpoints ) {
$match = preg_match( '@^' . $route . '$@i', $request->get_route(), $args );
if ( ! $match ) {
continue;
}
$data = $handler->get_data_for_route( $route, $endpoints, 'help' );
$accept = array_merge( $accept, $data['methods'] );
break;
}
$response->header( 'Accept', implode( ', ', $accept ) );
$response->set_data( $data );
return $response;
}
/**
* Sends the "Allow" header to state all methods that can be sent to the current route.
*
* @since 4.4.0
*
* @param WP_REST_Response $response Current response being served.
* @param WP_REST_Server $server ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request The request that was used to make current response.
* @return WP_REST_Response Response to be served, with "Allow" header if route has allowed methods.
*/
function rest_send_allow_header( $response, $server, $request ) {
$matched_route = $response->get_matched_route();
if ( ! $matched_route ) {
return $response;
}
$routes = $server->get_routes();
$allowed_methods = array();
// Get the allowed methods across the routes.
foreach ( $routes[ $matched_route ] as $_handler ) {
foreach ( $_handler['methods'] as $handler_method => $value ) {
if ( ! empty( $_handler['permission_callback'] ) ) {
$permission = call_user_func( $_handler['permission_callback'], $request );
$allowed_methods[ $handler_method ] = true === $permission;
} else {
$allowed_methods[ $handler_method ] = true;
}
}
}
// Strip out all the methods that are not allowed (false values).
$allowed_methods = array_filter( $allowed_methods );
if ( $allowed_methods ) {
$response->header( 'Allow', implode( ', ', array_map( 'strtoupper', array_keys( $allowed_methods ) ) ) );
}
return $response;
}
/**
* Adds the REST API URL to the WP RSD endpoint.
*
* @since 4.4.0
*
* @see get_rest_url()
*/
function rest_output_rsd() {
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
?>
<api name="WP-API" blogID="1" preferred="false" apiLink="<?php echo esc_url( $api_root ); ?>" />
<?php
}
/**
* Outputs the REST API link tag into page header.
*
* @since 4.4.0
*
* @see get_rest_url()
*/
function rest_output_link_wp_head() {
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
echo "<link rel='https://api.w.org/' href='" . esc_url( $api_root ) . "' />\n";
}
/**
* Sends a Link header for the REST API.
*
* @since 4.4.0
*/
function rest_output_link_header() {
if ( headers_sent() ) {
return;
}
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
header( 'Link: <' . esc_url_raw( $api_root ) . '>; rel="https://api.w.org/"', false );
}
/**
* Checks for errors when using cookie-based authentication.
*
* WordPress' built-in cookie authentication is always active
* for logged in users. However, the API has to check nonces
* for each request to ensure users are not vulnerable to CSRF.
*
* @since 4.4.0
*
* @global mixed $wp_rest_auth_cookie
*
* @param WP_Error|mixed $result Error from another authentication handler, null if we should handle it,
* or another value if not.
* @return WP_Error|mixed|bool WP_Error if the cookie is invalid, the $result, otherwise true.
*/
function rest_cookie_check_errors( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
global $wp_rest_auth_cookie;
/*
* Is cookie authentication being used? (If we get an auth
* error, but we're still logged in, another authentication
* must have been used).
*/
if ( true !== $wp_rest_auth_cookie && is_user_logged_in() ) {
return $result;
}
// Determine if there is a nonce.
$nonce = null;
if ( isset( $_REQUEST['_wpnonce'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
} elseif ( isset( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
$nonce = $_SERVER['HTTP_X_WP_NONCE'];
}
if ( null === $nonce ) {
// No nonce at all, so act as if it's an unauthenticated request.
wp_set_current_user( 0 );
return true;
}
// Check the nonce.
$result = wp_verify_nonce( $nonce, 'wp_rest' );
if ( ! $result ) {
return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie nonce is invalid' ), array( 'status' => 403 ) );
}
return true;
}
/**
* Collects cookie authentication status.
*
* Collects errors from wp_validate_auth_cookie for use by rest_cookie_check_errors.
*
* @since 4.4.0
*
* @see current_action()
* @global mixed $wp_rest_auth_cookie
*/
function rest_cookie_collect_status() {
global $wp_rest_auth_cookie;
$status_type = current_action();
if ( 'auth_cookie_valid' !== $status_type ) {
$wp_rest_auth_cookie = substr( $status_type, 12 );
return;
}
$wp_rest_auth_cookie = true;
}
/**
* Parses an RFC3339 timestamp into a DateTime.
*
* @since 4.4.0
*
* @param string $date RFC3339 timestamp.
* @param bool $force_utc Optional. Whether to force UTC timezone instead of using
* the timestamp's timezone. Default false.
* @return DateTime DateTime instance.
*/
function rest_parse_date( $date, $force_utc = false ) {
if ( $force_utc ) {
$date = preg_replace( '/[+-]\d+:?\d+$/', '+00:00', $date );
}
$regex = '#^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::\d{2})?)?$#';
if ( ! preg_match( $regex, $date, $matches ) ) {
return false;
}
return strtotime( $date );
}
/**
* Retrieves a local date with its GMT equivalent, in MySQL datetime format.
*
* @since 4.4.0
*
* @see rest_parse_date()
*
* @param string $date RFC3339 timestamp.
* @param bool $force_utc Whether a UTC timestamp should be forced. Default false.
* @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
* null on failure.
*/
function rest_get_date_with_gmt( $date, $force_utc = false ) {
$date = rest_parse_date( $date, $force_utc );
if ( empty( $date ) ) {
return null;
}
$utc = date( 'Y-m-d H:i:s', $date );
$local = get_date_from_gmt( $utc );
return array( $local, $utc );
}

View File

@ -1,643 +0,0 @@
<?php
/**
* REST API functions.
*
* @package WordPress
* @subpackage REST_API
* @since 4.4.0
*/
/**
* Registers a REST API route.
*
* @since 4.4.0
*
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*
* @param string $namespace The first URL segment after core prefix. Should be unique to your package/plugin.
* @param string $route The base URL for route you are adding.
* @param array $args Optional. Either an array of options for the endpoint, or an array of arrays for
* multiple methods. Default empty array.
* @param bool $override Optional. If the route already exists, should we override it? True overrides,
* false merges (with newer overriding if duplicate keys exist). Default false.
* @return bool True on success, false on error.
*/
function register_rest_route( $namespace, $route, $args = array(), $override = false ) {
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
if ( empty( $namespace ) ) {
/*
* Non-namespaced routes are not allowed, with the exception of the main
* and namespace indexes. If you really need to register a
* non-namespaced route, call `WP_REST_Server::register_route` directly.
*/
_doing_it_wrong( 'register_rest_route', 'Routes must be namespaced with plugin or theme name and version.', '4.4.0' );
return false;
} else if ( empty( $route ) ) {
_doing_it_wrong( 'register_rest_route', 'Route must be specified.', '4.4.0' );
return false;
}
if ( isset( $args['callback'] ) ) {
// Upgrade a single set to multiple.
$args = array( $args );
}
$defaults = array(
'methods' => 'GET',
'callback' => null,
'args' => array(),
);
foreach ( $args as $key => &$arg_group ) {
if ( ! is_numeric( $arg_group ) ) {
// Route option, skip here.
continue;
}
$arg_group = array_merge( $defaults, $arg_group );
}
$full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
$wp_rest_server->register_route( $namespace, $full_route, $args, $override );
return true;
}
/**
* Registers rewrite rules for the API.
*
* @since 4.4.0
*
* @see rest_api_register_rewrites()
* @global WP $wp Current WordPress environment instance.
*/
function rest_api_init() {
rest_api_register_rewrites();
global $wp;
$wp->add_query_var( 'rest_route' );
}
/**
* Adds REST rewrite rules.
*
* @since 4.4.0
*
* @see add_rewrite_rule()
*/
function rest_api_register_rewrites() {
add_rewrite_rule( '^' . rest_get_url_prefix() . '/?$','index.php?rest_route=/','top' );
add_rewrite_rule( '^' . rest_get_url_prefix() . '/(.*)?','index.php?rest_route=/$matches[1]','top' );
}
/**
* Registers the default REST API filters.
*
* Attached to the {@see 'rest_api_init'} action
* to make testing and disabling these filters easier.
*
* @since 4.4.0
*/
function rest_api_default_filters() {
// Deprecated reporting.
add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
add_filter( 'deprecated_function_trigger_error', '__return_false' );
add_action( 'deprecated_argument_run', 'rest_handle_deprecated_argument', 10, 3 );
add_filter( 'deprecated_argument_trigger_error', '__return_false' );
// Default serving.
add_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
add_filter( 'rest_post_dispatch', 'rest_send_allow_header', 10, 3 );
add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
}
/**
* Loads the REST API.
*
* @since 4.4.0
*
* @global WP $wp Current WordPress environment instance.
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*/
function rest_api_loaded() {
if ( empty( $GLOBALS['wp']->query_vars['rest_route'] ) ) {
return;
}
/**
* Whether this is a REST Request.
*
* @since 4.4.0
* @var bool
*/
define( 'REST_REQUEST', true );
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
/**
* Filter the REST Server Class.
*
* This filter allows you to adjust the server class used by the API, using a
* different class to handle requests.
*
* @since 4.4.0
*
* @param string $class_name The name of the server class. Default 'WP_REST_Server'.
*/
$wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
$wp_rest_server = new $wp_rest_server_class;
/**
* Fires when preparing to serve an API request.
*
* Endpoint objects should be created and register their hooks on this action rather
* than another action to ensure they're only loaded when needed.
*
* @since 4.4.0
*
* @param WP_REST_Server $wp_rest_server Server object.
*/
do_action( 'rest_api_init', $wp_rest_server );
// Fire off the request.
$wp_rest_server->serve_request( $GLOBALS['wp']->query_vars['rest_route'] );
// We're done.
die();
}
/**
* Retrieves the URL prefix for any API resource.
*
* @since 4.4.0
*
* @return string Prefix.
*/
function rest_get_url_prefix() {
/**
* Filter the REST URL prefix.
*
* @since 4.4.0
*
* @param string $prefix URL prefix. Default 'wp-json'.
*/
return apply_filters( 'rest_url_prefix', 'wp-json' );
}
/**
* Retrieves the URL to a REST endpoint on a site.
*
* Note: The returned URL is NOT escaped.
*
* @since 4.4.0
*
* @todo Check if this is even necessary
*
* @param int $blog_id Optional. Blog ID. Default of null returns URL for current blog.
* @param string $path Optional. REST route. Default '/'.
* @param string $scheme Optional. Sanitization scheme. Default 'rest'.
* @return string Full URL to the endpoint.
*/
function get_rest_url( $blog_id = null, $path = '/', $scheme = 'rest' ) {
if ( empty( $path ) ) {
$path = '/';
}
if ( is_multisite() && get_blog_option( $blog_id, 'permalink_structure' ) || get_option( 'permalink_structure' ) ) {
$url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
$url .= '/' . ltrim( $path, '/' );
} else {
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
$path = '/' . ltrim( $path, '/' );
$url = add_query_arg( 'rest_route', $path, $url );
}
if ( is_ssl() ) {
// If the current host is the same as the REST URL host, force the REST URL scheme to HTTPS.
if ( $_SERVER['SERVER_NAME'] === parse_url( get_home_url( $blog_id ), PHP_URL_HOST ) ) {
$url = set_url_scheme( $url, 'https' );
}
}
/**
* Filter the REST URL.
*
* Use this filter to adjust the url returned by the `get_rest_url` function.
*
* @since 4.4.0
*
* @param string $url REST URL.
* @param string $path REST route.
* @param int $blog_id Blog ID.
* @param string $scheme Sanitization scheme.
*/
return apply_filters( 'rest_url', $url, $path, $blog_id, $scheme );
}
/**
* Retrieves the URL to a REST endpoint.
*
* Note: The returned URL is NOT escaped.
*
* @since 4.4.0
*
* @param string $path Optional. REST route. Default empty.
* @param string $scheme Optional. Sanitization scheme. Default 'json'.
* @return string Full URL to the endpoint.
*/
function rest_url( $path = '', $scheme = 'json' ) {
return get_rest_url( null, $path, $scheme );
}
/**
* Do a REST request.
*
* Used primarily to route internal requests through WP_REST_Server.
*
* @since 4.4.0
*
* @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
*
* @param WP_REST_Request|string $request Request.
* @return WP_REST_Response REST response.
*/
function rest_do_request( $request ) {
global $wp_rest_server;
$request = rest_ensure_request( $request );
return $wp_rest_server->dispatch( $request );
}
/**
* Ensures request arguments are a request object (for consistency).
*
* @since 4.4.0
*
* @param array|WP_REST_Request $request Request to check.
* @return WP_REST_Request REST request instance.
*/
function rest_ensure_request( $request ) {
if ( $request instanceof WP_REST_Request ) {
return $request;
}
return new WP_REST_Request( 'GET', '', $request );
}
/**
* Ensures a REST response is a response object (for consistency).
*
* This implements WP_HTTP_Response, allowing usage of `set_status`/`header`/etc
* without needing to double-check the object. Will also allow WP_Error to indicate error
* responses, so users should immediately check for this value.
*
* @since 4.4.0
*
* @param WP_Error|WP_HTTP_Response|mixed $response Response to check.
* @return mixed WP_Error if response generated an error, WP_HTTP_Response if response
* is a already an instance, otherwise returns a new WP_REST_Response instance.
*/
function rest_ensure_response( $response ) {
if ( is_wp_error( $response ) ) {
return $response;
}
if ( $response instanceof WP_HTTP_Response ) {
return $response;
}
return new WP_REST_Response( $response );
}
/**
* Handles _deprecated_function() errors.
*
* @since 4.4.0
*
* @param string $function Function name.
* @param string $replacement Replacement function name.
* @param string $version Version.
*/
function rest_handle_deprecated_function( $function, $replacement, $version ) {
if ( ! empty( $replacement ) ) {
/* translators: 1: function name, 2: WordPress version number, 3: new function name */
$string = sprintf( __( '%1$s (since %2$s; use %3$s instead)' ), $function, $version, $replacement );
} else {
/* translators: 1: function name, 2: WordPress version number */
$string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
}
header( sprintf( 'X-WP-DeprecatedFunction: %s', $string ) );
}
/**
* Handles _deprecated_argument() errors.
*
* @since 4.4.0
*
* @param string $function Function name.
* @param string $replacement Replacement function name.
* @param string $version Version.
*/
function rest_handle_deprecated_argument( $function, $replacement, $version ) {
if ( ! empty( $replacement ) ) {
/* translators: 1: function name, 2: WordPress version number, 3: new argument name */
$string = sprintf( __( '%1$s (since %2$s; %3$s)' ), $function, $version, $replacement );
} else {
/* translators: 1: function name, 2: WordPress version number */
$string = sprintf( __( '%1$s (since %2$s; no alternative available)' ), $function, $version );
}
header( sprintf( 'X-WP-DeprecatedParam: %s', $string ) );
}
/**
* Sends Cross-Origin Resource Sharing headers with API requests.
*
* @since 4.4.0
*
* @param mixed $value Response data.
* @return mixed Response data.
*/
function rest_send_cors_headers( $value ) {
$origin = get_http_origin();
if ( $origin ) {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
header( 'Access-Control-Allow-Credentials: true' );
}
return $value;
}
/**
* Handles OPTIONS requests for the server.
*
* This is handled outside of the server code, as it doesn't obey normal route
* mapping.
*
* @since 4.4.0
*
* @param mixed $response Current response, either response or `null` to indicate pass-through.
* @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request The request that was used to make current response.
* @return WP_REST_Response Modified response, either response or `null` to indicate pass-through.
*/
function rest_handle_options_request( $response, $handler, $request ) {
if ( ! empty( $response ) || $request->get_method() !== 'OPTIONS' ) {
return $response;
}
$response = new WP_REST_Response();
$data = array();
$accept = array();
foreach ( $handler->get_routes() as $route => $endpoints ) {
$match = preg_match( '@^' . $route . '$@i', $request->get_route(), $args );
if ( ! $match ) {
continue;
}
$data = $handler->get_data_for_route( $route, $endpoints, 'help' );
$accept = array_merge( $accept, $data['methods'] );
break;
}
$response->header( 'Accept', implode( ', ', $accept ) );
$response->set_data( $data );
return $response;
}
/**
* Sends the "Allow" header to state all methods that can be sent to the current route.
*
* @since 4.4.0
*
* @param WP_REST_Response $response Current response being served.
* @param WP_REST_Server $server ResponseHandler instance (usually WP_REST_Server).
* @param WP_REST_Request $request The request that was used to make current response.
* @return WP_REST_Response Response to be served, with "Allow" header if route has allowed methods.
*/
function rest_send_allow_header( $response, $server, $request ) {
$matched_route = $response->get_matched_route();
if ( ! $matched_route ) {
return $response;
}
$routes = $server->get_routes();
$allowed_methods = array();
// Get the allowed methods across the routes.
foreach ( $routes[ $matched_route ] as $_handler ) {
foreach ( $_handler['methods'] as $handler_method => $value ) {
if ( ! empty( $_handler['permission_callback'] ) ) {
$permission = call_user_func( $_handler['permission_callback'], $request );
$allowed_methods[ $handler_method ] = true === $permission;
} else {
$allowed_methods[ $handler_method ] = true;
}
}
}
// Strip out all the methods that are not allowed (false values).
$allowed_methods = array_filter( $allowed_methods );
if ( $allowed_methods ) {
$response->header( 'Allow', implode( ', ', array_map( 'strtoupper', array_keys( $allowed_methods ) ) ) );
}
return $response;
}
/**
* Adds the REST API URL to the WP RSD endpoint.
*
* @since 4.4.0
*
* @see get_rest_url()
*/
function rest_output_rsd() {
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
?>
<api name="WP-API" blogID="1" preferred="false" apiLink="<?php echo esc_url( $api_root ); ?>" />
<?php
}
/**
* Outputs the REST API link tag into page header.
*
* @since 4.4.0
*
* @see get_rest_url()
*/
function rest_output_link_wp_head() {
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
echo "<link rel='https://api.w.org/' href='" . esc_url( $api_root ) . "' />\n";
}
/**
* Sends a Link header for the REST API.
*
* @since 4.4.0
*/
function rest_output_link_header() {
if ( headers_sent() ) {
return;
}
$api_root = get_rest_url();
if ( empty( $api_root ) ) {
return;
}
header( 'Link: <' . esc_url_raw( $api_root ) . '>; rel="https://api.w.org/"', false );
}
/**
* Checks for errors when using cookie-based authentication.
*
* WordPress' built-in cookie authentication is always active
* for logged in users. However, the API has to check nonces
* for each request to ensure users are not vulnerable to CSRF.
*
* @since 4.4.0
*
* @global mixed $wp_rest_auth_cookie
*
* @param WP_Error|mixed $result Error from another authentication handler, null if we should handle it,
* or another value if not.
* @return WP_Error|mixed|bool WP_Error if the cookie is invalid, the $result, otherwise true.
*/
function rest_cookie_check_errors( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
global $wp_rest_auth_cookie;
/*
* Is cookie authentication being used? (If we get an auth
* error, but we're still logged in, another authentication
* must have been used).
*/
if ( true !== $wp_rest_auth_cookie && is_user_logged_in() ) {
return $result;
}
// Determine if there is a nonce.
$nonce = null;
if ( isset( $_REQUEST['_wpnonce'] ) ) {
$nonce = $_REQUEST['_wpnonce'];
} elseif ( isset( $_SERVER['HTTP_X_WP_NONCE'] ) ) {
$nonce = $_SERVER['HTTP_X_WP_NONCE'];
}
if ( null === $nonce ) {
// No nonce at all, so act as if it's an unauthenticated request.
wp_set_current_user( 0 );
return true;
}
// Check the nonce.
$result = wp_verify_nonce( $nonce, 'wp_rest' );
if ( ! $result ) {
return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie nonce is invalid' ), array( 'status' => 403 ) );
}
return true;
}
/**
* Collects cookie authentication status.
*
* Collects errors from wp_validate_auth_cookie for use by rest_cookie_check_errors.
*
* @since 4.4.0
*
* @see current_action()
* @global mixed $wp_rest_auth_cookie
*/
function rest_cookie_collect_status() {
global $wp_rest_auth_cookie;
$status_type = current_action();
if ( 'auth_cookie_valid' !== $status_type ) {
$wp_rest_auth_cookie = substr( $status_type, 12 );
return;
}
$wp_rest_auth_cookie = true;
}
/**
* Parses an RFC3339 timestamp into a DateTime.
*
* @since 4.4.0
*
* @param string $date RFC3339 timestamp.
* @param bool $force_utc Optional. Whether to force UTC timezone instead of using
* the timestamp's timezone. Default false.
* @return DateTime DateTime instance.
*/
function rest_parse_date( $date, $force_utc = false ) {
if ( $force_utc ) {
$date = preg_replace( '/[+-]\d+:?\d+$/', '+00:00', $date );
}
$regex = '#^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::\d{2})?)?$#';
if ( ! preg_match( $regex, $date, $matches ) ) {
return false;
}
return strtotime( $date );
}
/**
* Retrieves a local date with its GMT equivalent, in MySQL datetime format.
*
* @since 4.4.0
*
* @see rest_parse_date()
*
* @param string $date RFC3339 timestamp.
* @param bool $force_utc Whether a UTC timestamp should be forced. Default false.
* @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
* null on failure.
*/
function rest_get_date_with_gmt( $date, $force_utc = false ) {
$date = rest_parse_date( $date, $force_utc );
if ( empty( $date ) ) {
return null;
}
$utc = date( 'Y-m-d H:i:s', $date );
$local = get_date_from_gmt( $utc );
return array( $local, $utc );
}

View File

@ -1,120 +0,0 @@
<?php
/**
* Rewrite API: Constants
*
* @package WordPress
* @subpackage Rewrite
* @since 4.4.0
*/
/**
* Endpoint Mask for default, which is nothing.
*
* @since 2.1.0
*/
define('EP_NONE', 0);
/**
* Endpoint Mask for Permalink.
*
* @since 2.1.0
*/
define('EP_PERMALINK', 1);
/**
* Endpoint Mask for Attachment.
*
* @since 2.1.0
*/
define('EP_ATTACHMENT', 2);
/**
* Endpoint Mask for date.
*
* @since 2.1.0
*/
define('EP_DATE', 4);
/**
* Endpoint Mask for year
*
* @since 2.1.0
*/
define('EP_YEAR', 8);
/**
* Endpoint Mask for month.
*
* @since 2.1.0
*/
define('EP_MONTH', 16);
/**
* Endpoint Mask for day.
*
* @since 2.1.0
*/
define('EP_DAY', 32);
/**
* Endpoint Mask for root.
*
* @since 2.1.0
*/
define('EP_ROOT', 64);
/**
* Endpoint Mask for comments.
*
* @since 2.1.0
*/
define('EP_COMMENTS', 128);
/**
* Endpoint Mask for searches.
*
* @since 2.1.0
*/
define('EP_SEARCH', 256);
/**
* Endpoint Mask for categories.
*
* @since 2.1.0
*/
define('EP_CATEGORIES', 512);
/**
* Endpoint Mask for tags.
*
* @since 2.3.0
*/
define('EP_TAGS', 1024);
/**
* Endpoint Mask for authors.
*
* @since 2.1.0
*/
define('EP_AUTHORS', 2048);
/**
* Endpoint Mask for pages.
*
* @since 2.1.0
*/
define('EP_PAGES', 4096);
/**
* Endpoint Mask for all archive views.
*
* @since 3.7.0
*/
define( 'EP_ALL_ARCHIVES', EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS );
/**
* Endpoint Mask for everything.
*
* @since 2.1.0
*/
define( 'EP_ALL', EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES );

View File

@ -1,445 +0,0 @@
<?php
/**
* WordPress Rewrite API
*
* @package WordPress
* @subpackage Rewrite
*/
/**
* Adds a rewrite rule that transforms a URL structure to a set of query vars.
*
* Any value in the $after parameter that isn't 'bottom' will result in the rule
* being placed at the top of the rewrite rules.
*
* @since 2.1.0
* @since 4.4.0 Array support was added to the `$query` parameter.
*
* @global WP_Rewrite $wp_rewrite WordPress Rewrite Component.
*
* @param string $regex Regular expression to match request against.
* @param string|array $query The corresponding query vars for this rewrite rule.
* @param string $after Optional. Priority of the new rule. Accepts 'top'
* or 'bottom'. Default 'bottom'.
*/
function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $query, $after );
}
/**
* Add a new rewrite tag (like %postname%).
*
* The $query parameter is optional. If it is omitted you must ensure that
* you call this on, or before, the 'init' hook. This is because $query defaults
* to "$tag=", and for this to work a new query var has to be added.
*
* @since 2.1.0
*
* @global WP_Rewrite $wp_rewrite
* @global WP $wp
*
* @param string $tag Name of the new rewrite tag.
* @param string $regex Regular expression to substitute the tag for in rewrite rules.
* @param string $query Optional. String to append to the rewritten query. Must end in '='. Default empty.
*/
function add_rewrite_tag( $tag, $regex, $query = '' ) {
// validate the tag's name
if ( strlen( $tag ) < 3 || $tag[0] != '%' || $tag[ strlen($tag) - 1 ] != '%' )
return;
global $wp_rewrite, $wp;
if ( empty( $query ) ) {
$qv = trim( $tag, '%' );
$wp->add_query_var( $qv );
$query = $qv . '=';
}
$wp_rewrite->add_rewrite_tag( $tag, $regex, $query );
}
/**
* Add permalink structure.
*
* @since 3.0.0
*
* @see WP_Rewrite::add_permastruct()
* @global WP_Rewrite $wp_rewrite
*
* @param string $name Name for permalink structure.
* @param string $struct Permalink structure.
* @param array $args Optional. Arguments for building the rules from the permalink structure,
* see WP_Rewrite::add_permastruct() for full details. Default empty array.
*/
function add_permastruct( $name, $struct, $args = array() ) {
global $wp_rewrite;
// backwards compatibility for the old parameters: $with_front and $ep_mask
if ( ! is_array( $args ) )
$args = array( 'with_front' => $args );
if ( func_num_args() == 4 )
$args['ep_mask'] = func_get_arg( 3 );
$wp_rewrite->add_permastruct( $name, $struct, $args );
}
/**
* Add a new feed type like /atom1/.
*
* @since 2.1.0
*
* @global WP_Rewrite $wp_rewrite
*
* @param string $feedname Feed name.
* @param callable $function Callback to run on feed display.
* @return string Feed action name.
*/
function add_feed( $feedname, $function ) {
global $wp_rewrite;
if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
$wp_rewrite->feeds[] = $feedname;
}
$hook = 'do_feed_' . $feedname;
// Remove default function hook
remove_action( $hook, $hook );
add_action( $hook, $function, 10, 2 );
return $hook;
}
/**
* Remove rewrite rules and then recreate rewrite rules.
*
* @since 3.0.0
*
* @global WP_Rewrite $wp_rewrite
*
* @param bool $hard Whether to update .htaccess (hard flush) or just update
* rewrite_rules transient (soft flush). Default is true (hard).
*/
function flush_rewrite_rules( $hard = true ) {
global $wp_rewrite;
$wp_rewrite->flush_rules( $hard );
}
/**
* Add an endpoint, like /trackback/.
*
* Adding an endpoint creates extra rewrite rules for each of the matching
* places specified by the provided bitmask. For example:
*
* add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );
*
* will add a new rewrite rule ending with "json(/(.*))?/?$" for every permastruct
* that describes a permalink (post) or page. This is rewritten to "json=$match"
* where $match is the part of the URL matched by the endpoint regex (e.g. "foo" in
* "[permalink]/json/foo/").
*
* A new query var with the same name as the endpoint will also be created.
*
* When specifying $places ensure that you are using the EP_* constants (or a
* combination of them using the bitwise OR operator) as their values are not
* guaranteed to remain static (especially `EP_ALL`).
*
* Be sure to flush the rewrite rules - see flush_rewrite_rules() - when your plugin gets
* activated and deactivated.
*
* @since 2.1.0
* @since 4.3.0 Added support for skipping query var registration by passing `false` to `$query_var`.
*
* @global WP_Rewrite $wp_rewrite
*
* @param string $name Name of the endpoint.
* @param int $places Endpoint mask describing the places the endpoint should be added.
* @param string|bool $query_var Name of the corresponding query variable. Pass `false` to skip registering a query_var
* for this endpoint. Defaults to the value of `$name`.
*/
function add_rewrite_endpoint( $name, $places, $query_var = true ) {
global $wp_rewrite;
$wp_rewrite->add_endpoint( $name, $places, $query_var );
}
/**
* Filter the URL base for taxonomies.
*
* To remove any manually prepended /index.php/.
*
* @access private
* @since 2.6.0
*
* @param string $base The taxonomy base that we're going to filter
* @return string
*/
function _wp_filter_taxonomy_base( $base ) {
if ( !empty( $base ) ) {
$base = preg_replace( '|^/index\.php/|', '', $base );
$base = trim( $base, '/' );
}
return $base;
}
/**
* Resolve numeric slugs that collide with date permalinks.
*
* Permalinks of posts with numeric slugs can sometimes look to WP_Query::parse_query()
* like a date archive, as when your permalink structure is `/%year%/%postname%/` and
* a post with post_name '05' has the URL `/2015/05/`.
*
* This function detects conflicts of this type and resolves them in favor of the
* post permalink.
*
* Note that, since 4.3.0, wp_unique_post_slug() prevents the creation of post slugs
* that would result in a date archive conflict. The resolution performed in this
* function is primarily for legacy content, as well as cases when the admin has changed
* the site's permalink structure in a way that introduces URL conflicts.
*
* @since 4.3.0
*
* @param array $query_vars Optional. Query variables for setting up the loop, as determined in
* WP::parse_request(). Default empty array.
* @return array Returns the original array of query vars, with date/post conflicts resolved.
*/
function wp_resolve_numeric_slug_conflicts( $query_vars = array() ) {
if ( ! isset( $query_vars['year'] ) && ! isset( $query_vars['monthnum'] ) && ! isset( $query_vars['day'] ) ) {
return $query_vars;
}
// Identify the 'postname' position in the permastruct array.
$permastructs = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
$postname_index = array_search( '%postname%', $permastructs );
if ( false === $postname_index ) {
return $query_vars;
}
/*
* A numeric slug could be confused with a year, month, or day, depending on position. To account for
* the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our
* `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check
* for month-slug clashes when `is_month` *or* `is_day`.
*/
$compare = '';
if ( 0 === $postname_index && ( isset( $query_vars['year'] ) || isset( $query_vars['monthnum'] ) ) ) {
$compare = 'year';
} elseif ( '%year%' === $permastructs[ $postname_index - 1 ] && ( isset( $query_vars['monthnum'] ) || isset( $query_vars['day'] ) ) ) {
$compare = 'monthnum';
} elseif ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && isset( $query_vars['day'] ) ) {
$compare = 'day';
}
if ( ! $compare ) {
return $query_vars;
}
// This is the potentially clashing slug.
$value = $query_vars[ $compare ];
$post = get_page_by_path( $value, OBJECT, 'post' );
if ( ! ( $post instanceof WP_Post ) ) {
return $query_vars;
}
// If the date of the post doesn't match the date specified in the URL, resolve to the date archive.
if ( preg_match( '/^([0-9]{4})\-([0-9]{2})/', $post->post_date, $matches ) && isset( $query_vars['year'] ) && ( 'monthnum' === $compare || 'day' === $compare ) ) {
// $matches[1] is the year the post was published.
if ( intval( $query_vars['year'] ) !== intval( $matches[1] ) ) {
return $query_vars;
}
// $matches[2] is the month the post was published.
if ( 'day' === $compare && isset( $query_vars['monthnum'] ) && intval( $query_vars['monthnum'] ) !== intval( $matches[2] ) ) {
return $query_vars;
}
}
/*
* If the located post contains nextpage pagination, then the URL chunk following postname may be
* intended as the page number. Verify that it's a valid page before resolving to it.
*/
$maybe_page = '';
if ( 'year' === $compare && isset( $query_vars['monthnum'] ) ) {
$maybe_page = $query_vars['monthnum'];
} elseif ( 'monthnum' === $compare && isset( $query_vars['day'] ) ) {
$maybe_page = $query_vars['day'];
}
// Bug found in #11694 - 'page' was returning '/4'
$maybe_page = (int) trim( $maybe_page, '/' );
$post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1;
// If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive.
if ( 1 === $post_page_count && $maybe_page ) {
return $query_vars;
}
// If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive.
if ( $post_page_count > 1 && $maybe_page > $post_page_count ) {
return $query_vars;
}
// If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage.
if ( '' !== $maybe_page ) {
$query_vars['page'] = intval( $maybe_page );
}
// Next, unset autodetected date-related query vars.
unset( $query_vars['year'] );
unset( $query_vars['monthnum'] );
unset( $query_vars['day'] );
// Then, set the identified post.
$query_vars['name'] = $post->post_name;
// Finally, return the modified query vars.
return $query_vars;
}
/**
* Examine a url and try to determine the post ID it represents.
*
* Checks are supposedly from the hosted site blog.
*
* @since 1.0.0
*
* @global WP_Rewrite $wp_rewrite
* @global WP $wp
*
* @param string $url Permalink to check.
* @return int Post ID, or 0 on failure.
*/
function url_to_postid( $url ) {
global $wp_rewrite;
/**
* Filter the URL to derive the post ID from.
*
* @since 2.2.0
*
* @param string $url The URL to derive the post ID from.
*/
$url = apply_filters( 'url_to_postid', $url );
// First, check to see if there is a 'p=N' or 'page_id=N' to match against
if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
$id = absint($values[2]);
if ( $id )
return $id;
}
// Check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();
// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
if ( empty($rewrite) )
return 0;
// Get rid of the #anchor
$url_split = explode('#', $url);
$url = $url_split[0];
// Get rid of URL ?query=string
$url_split = explode('?', $url);
$url = $url_split[0];
// Set the correct URL scheme.
$url = set_url_scheme( $url );
// Add 'www.' if it is absent and should be there
if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
$url = str_replace('://', '://www.', $url);
// Strip 'www.' if it is present and shouldn't be
if ( false === strpos(home_url(), '://www.') )
$url = str_replace('://www.', '://', $url);
// Strip 'index.php/' if we're not using path info permalinks
if ( !$wp_rewrite->using_index_permalinks() )
$url = str_replace( $wp_rewrite->index . '/', '', $url );
if ( false !== strpos( trailingslashit( $url ), home_url( '/' ) ) ) {
// Chop off http://domain.com/[path]
$url = str_replace(home_url(), '', $url);
} else {
// Chop off /path/to/blog
$home_path = parse_url( home_url( '/' ) );
$home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
$url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( $url ) );
}
// Trim leading and lagging slashes
$url = trim($url, '/');
$request = $url;
$post_type_query_vars = array();
foreach ( get_post_types( array() , 'objects' ) as $post_type => $t ) {
if ( ! empty( $t->query_var ) )
$post_type_query_vars[ $t->query_var ] = $post_type;
}
// Look for matches.
$request_match = $request;
foreach ( (array)$rewrite as $match => $query) {
// If the requesting file is the anchor of the match, prepend it
// to the path info.
if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
$request_match = $url . '/' . $request;
if ( preg_match("#^$match#", $request_match, $matches) ) {
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
$page = get_page_by_path( $matches[ $varmatch[1] ] );
if ( ! $page ) {
continue;
}
$post_status_obj = get_post_status_object( $page->post_status );
if ( ! $post_status_obj->public && ! $post_status_obj->protected
&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
continue;
}
}
// Got a match.
// Trim the query of everything up to the '?'.
$query = preg_replace("!^.+\?!", '', $query);
// Substitute the substring matches into the query.
$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
// Filter out non-public query vars
global $wp;
parse_str( $query, $query_vars );
$query = array();
foreach ( (array) $query_vars as $key => $value ) {
if ( in_array( $key, $wp->public_query_vars ) ){
$query[$key] = $value;
if ( isset( $post_type_query_vars[$key] ) ) {
$query['post_type'] = $post_type_query_vars[$key];
$query['name'] = $value;
}
}
}
// Resolve conflicts between posts with numeric slugs and date archive queries.
$query = wp_resolve_numeric_slug_conflicts( $query );
// Do the query
$query = new WP_Query( $query );
if ( ! empty( $query->posts ) && $query->is_singular )
return $query->post->ID;
else
return 0;
}
}
return 0;
}

View File

@ -6,6 +6,552 @@
* @subpackage Rewrite
*/
require_once( ABSPATH . WPINC . '/rewrite-constants.php' );
require_once( ABSPATH . WPINC . '/rewrite-functions.php' );
require_once( ABSPATH . WPINC . '/class-wp-rewrite.php' );
/**
* Endpoint Mask for default, which is nothing.
*
* @since 2.1.0
*/
define('EP_NONE', 0);
/**
* Endpoint Mask for Permalink.
*
* @since 2.1.0
*/
define('EP_PERMALINK', 1);
/**
* Endpoint Mask for Attachment.
*
* @since 2.1.0
*/
define('EP_ATTACHMENT', 2);
/**
* Endpoint Mask for date.
*
* @since 2.1.0
*/
define('EP_DATE', 4);
/**
* Endpoint Mask for year
*
* @since 2.1.0
*/
define('EP_YEAR', 8);
/**
* Endpoint Mask for month.
*
* @since 2.1.0
*/
define('EP_MONTH', 16);
/**
* Endpoint Mask for day.
*
* @since 2.1.0
*/
define('EP_DAY', 32);
/**
* Endpoint Mask for root.
*
* @since 2.1.0
*/
define('EP_ROOT', 64);
/**
* Endpoint Mask for comments.
*
* @since 2.1.0
*/
define('EP_COMMENTS', 128);
/**
* Endpoint Mask for searches.
*
* @since 2.1.0
*/
define('EP_SEARCH', 256);
/**
* Endpoint Mask for categories.
*
* @since 2.1.0
*/
define('EP_CATEGORIES', 512);
/**
* Endpoint Mask for tags.
*
* @since 2.3.0
*/
define('EP_TAGS', 1024);
/**
* Endpoint Mask for authors.
*
* @since 2.1.0
*/
define('EP_AUTHORS', 2048);
/**
* Endpoint Mask for pages.
*
* @since 2.1.0
*/
define('EP_PAGES', 4096);
/**
* Endpoint Mask for all archive views.
*
* @since 3.7.0
*/
define( 'EP_ALL_ARCHIVES', EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS );
/**
* Endpoint Mask for everything.
*
* @since 2.1.0
*/
define( 'EP_ALL', EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES );
/**
* Adds a rewrite rule that transforms a URL structure to a set of query vars.
*
* Any value in the $after parameter that isn't 'bottom' will result in the rule
* being placed at the top of the rewrite rules.
*
* @since 2.1.0
* @since 4.4.0 Array support was added to the `$query` parameter.
*
* @global WP_Rewrite $wp_rewrite WordPress Rewrite Component.
*
* @param string $regex Regular expression to match request against.
* @param string|array $query The corresponding query vars for this rewrite rule.
* @param string $after Optional. Priority of the new rule. Accepts 'top'
* or 'bottom'. Default 'bottom'.
*/
function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $query, $after );
}
/**
* Add a new rewrite tag (like %postname%).
*
* The $query parameter is optional. If it is omitted you must ensure that
* you call this on, or before, the 'init' hook. This is because $query defaults
* to "$tag=", and for this to work a new query var has to be added.
*
* @since 2.1.0
*
* @global WP_Rewrite $wp_rewrite
* @global WP $wp
*
* @param string $tag Name of the new rewrite tag.
* @param string $regex Regular expression to substitute the tag for in rewrite rules.
* @param string $query Optional. String to append to the rewritten query. Must end in '='. Default empty.
*/
function add_rewrite_tag( $tag, $regex, $query = '' ) {
// validate the tag's name
if ( strlen( $tag ) < 3 || $tag[0] != '%' || $tag[ strlen($tag) - 1 ] != '%' )
return;
global $wp_rewrite, $wp;
if ( empty( $query ) ) {
$qv = trim( $tag, '%' );
$wp->add_query_var( $qv );
$query = $qv . '=';
}
$wp_rewrite->add_rewrite_tag( $tag, $regex, $query );
}
/**
* Add permalink structure.
*
* @since 3.0.0
*
* @see WP_Rewrite::add_permastruct()
* @global WP_Rewrite $wp_rewrite
*
* @param string $name Name for permalink structure.
* @param string $struct Permalink structure.
* @param array $args Optional. Arguments for building the rules from the permalink structure,
* see WP_Rewrite::add_permastruct() for full details. Default empty array.
*/
function add_permastruct( $name, $struct, $args = array() ) {
global $wp_rewrite;
// backwards compatibility for the old parameters: $with_front and $ep_mask
if ( ! is_array( $args ) )
$args = array( 'with_front' => $args );
if ( func_num_args() == 4 )
$args['ep_mask'] = func_get_arg( 3 );
$wp_rewrite->add_permastruct( $name, $struct, $args );
}
/**
* Add a new feed type like /atom1/.
*
* @since 2.1.0
*
* @global WP_Rewrite $wp_rewrite
*
* @param string $feedname Feed name.
* @param callable $function Callback to run on feed display.
* @return string Feed action name.
*/
function add_feed( $feedname, $function ) {
global $wp_rewrite;
if ( ! in_array( $feedname, $wp_rewrite->feeds ) ) {
$wp_rewrite->feeds[] = $feedname;
}
$hook = 'do_feed_' . $feedname;
// Remove default function hook
remove_action( $hook, $hook );
add_action( $hook, $function, 10, 2 );
return $hook;
}
/**
* Remove rewrite rules and then recreate rewrite rules.
*
* @since 3.0.0
*
* @global WP_Rewrite $wp_rewrite
*
* @param bool $hard Whether to update .htaccess (hard flush) or just update
* rewrite_rules transient (soft flush). Default is true (hard).
*/
function flush_rewrite_rules( $hard = true ) {
global $wp_rewrite;
$wp_rewrite->flush_rules( $hard );
}
/**
* Add an endpoint, like /trackback/.
*
* Adding an endpoint creates extra rewrite rules for each of the matching
* places specified by the provided bitmask. For example:
*
* add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );
*
* will add a new rewrite rule ending with "json(/(.*))?/?$" for every permastruct
* that describes a permalink (post) or page. This is rewritten to "json=$match"
* where $match is the part of the URL matched by the endpoint regex (e.g. "foo" in
* "[permalink]/json/foo/").
*
* A new query var with the same name as the endpoint will also be created.
*
* When specifying $places ensure that you are using the EP_* constants (or a
* combination of them using the bitwise OR operator) as their values are not
* guaranteed to remain static (especially `EP_ALL`).
*
* Be sure to flush the rewrite rules - see flush_rewrite_rules() - when your plugin gets
* activated and deactivated.
*
* @since 2.1.0
* @since 4.3.0 Added support for skipping query var registration by passing `false` to `$query_var`.
*
* @global WP_Rewrite $wp_rewrite
*
* @param string $name Name of the endpoint.
* @param int $places Endpoint mask describing the places the endpoint should be added.
* @param string|bool $query_var Name of the corresponding query variable. Pass `false` to skip registering a query_var
* for this endpoint. Defaults to the value of `$name`.
*/
function add_rewrite_endpoint( $name, $places, $query_var = true ) {
global $wp_rewrite;
$wp_rewrite->add_endpoint( $name, $places, $query_var );
}
/**
* Filter the URL base for taxonomies.
*
* To remove any manually prepended /index.php/.
*
* @access private
* @since 2.6.0
*
* @param string $base The taxonomy base that we're going to filter
* @return string
*/
function _wp_filter_taxonomy_base( $base ) {
if ( !empty( $base ) ) {
$base = preg_replace( '|^/index\.php/|', '', $base );
$base = trim( $base, '/' );
}
return $base;
}
/**
* Resolve numeric slugs that collide with date permalinks.
*
* Permalinks of posts with numeric slugs can sometimes look to WP_Query::parse_query()
* like a date archive, as when your permalink structure is `/%year%/%postname%/` and
* a post with post_name '05' has the URL `/2015/05/`.
*
* This function detects conflicts of this type and resolves them in favor of the
* post permalink.
*
* Note that, since 4.3.0, wp_unique_post_slug() prevents the creation of post slugs
* that would result in a date archive conflict. The resolution performed in this
* function is primarily for legacy content, as well as cases when the admin has changed
* the site's permalink structure in a way that introduces URL conflicts.
*
* @since 4.3.0
*
* @param array $query_vars Optional. Query variables for setting up the loop, as determined in
* WP::parse_request(). Default empty array.
* @return array Returns the original array of query vars, with date/post conflicts resolved.
*/
function wp_resolve_numeric_slug_conflicts( $query_vars = array() ) {
if ( ! isset( $query_vars['year'] ) && ! isset( $query_vars['monthnum'] ) && ! isset( $query_vars['day'] ) ) {
return $query_vars;
}
// Identify the 'postname' position in the permastruct array.
$permastructs = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
$postname_index = array_search( '%postname%', $permastructs );
if ( false === $postname_index ) {
return $query_vars;
}
/*
* A numeric slug could be confused with a year, month, or day, depending on position. To account for
* the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our
* `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check
* for month-slug clashes when `is_month` *or* `is_day`.
*/
$compare = '';
if ( 0 === $postname_index && ( isset( $query_vars['year'] ) || isset( $query_vars['monthnum'] ) ) ) {
$compare = 'year';
} elseif ( '%year%' === $permastructs[ $postname_index - 1 ] && ( isset( $query_vars['monthnum'] ) || isset( $query_vars['day'] ) ) ) {
$compare = 'monthnum';
} elseif ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && isset( $query_vars['day'] ) ) {
$compare = 'day';
}
if ( ! $compare ) {
return $query_vars;
}
// This is the potentially clashing slug.
$value = $query_vars[ $compare ];
$post = get_page_by_path( $value, OBJECT, 'post' );
if ( ! ( $post instanceof WP_Post ) ) {
return $query_vars;
}
// If the date of the post doesn't match the date specified in the URL, resolve to the date archive.
if ( preg_match( '/^([0-9]{4})\-([0-9]{2})/', $post->post_date, $matches ) && isset( $query_vars['year'] ) && ( 'monthnum' === $compare || 'day' === $compare ) ) {
// $matches[1] is the year the post was published.
if ( intval( $query_vars['year'] ) !== intval( $matches[1] ) ) {
return $query_vars;
}
// $matches[2] is the month the post was published.
if ( 'day' === $compare && isset( $query_vars['monthnum'] ) && intval( $query_vars['monthnum'] ) !== intval( $matches[2] ) ) {
return $query_vars;
}
}
/*
* If the located post contains nextpage pagination, then the URL chunk following postname may be
* intended as the page number. Verify that it's a valid page before resolving to it.
*/
$maybe_page = '';
if ( 'year' === $compare && isset( $query_vars['monthnum'] ) ) {
$maybe_page = $query_vars['monthnum'];
} elseif ( 'monthnum' === $compare && isset( $query_vars['day'] ) ) {
$maybe_page = $query_vars['day'];
}
// Bug found in #11694 - 'page' was returning '/4'
$maybe_page = (int) trim( $maybe_page, '/' );
$post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1;
// If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive.
if ( 1 === $post_page_count && $maybe_page ) {
return $query_vars;
}
// If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive.
if ( $post_page_count > 1 && $maybe_page > $post_page_count ) {
return $query_vars;
}
// If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage.
if ( '' !== $maybe_page ) {
$query_vars['page'] = intval( $maybe_page );
}
// Next, unset autodetected date-related query vars.
unset( $query_vars['year'] );
unset( $query_vars['monthnum'] );
unset( $query_vars['day'] );
// Then, set the identified post.
$query_vars['name'] = $post->post_name;
// Finally, return the modified query vars.
return $query_vars;
}
/**
* Examine a url and try to determine the post ID it represents.
*
* Checks are supposedly from the hosted site blog.
*
* @since 1.0.0
*
* @global WP_Rewrite $wp_rewrite
* @global WP $wp
*
* @param string $url Permalink to check.
* @return int Post ID, or 0 on failure.
*/
function url_to_postid( $url ) {
global $wp_rewrite;
/**
* Filter the URL to derive the post ID from.
*
* @since 2.2.0
*
* @param string $url The URL to derive the post ID from.
*/
$url = apply_filters( 'url_to_postid', $url );
// First, check to see if there is a 'p=N' or 'page_id=N' to match against
if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
$id = absint($values[2]);
if ( $id )
return $id;
}
// Check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();
// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
if ( empty($rewrite) )
return 0;
// Get rid of the #anchor
$url_split = explode('#', $url);
$url = $url_split[0];
// Get rid of URL ?query=string
$url_split = explode('?', $url);
$url = $url_split[0];
// Set the correct URL scheme.
$url = set_url_scheme( $url );
// Add 'www.' if it is absent and should be there
if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
$url = str_replace('://', '://www.', $url);
// Strip 'www.' if it is present and shouldn't be
if ( false === strpos(home_url(), '://www.') )
$url = str_replace('://www.', '://', $url);
// Strip 'index.php/' if we're not using path info permalinks
if ( !$wp_rewrite->using_index_permalinks() )
$url = str_replace( $wp_rewrite->index . '/', '', $url );
if ( false !== strpos( trailingslashit( $url ), home_url( '/' ) ) ) {
// Chop off http://domain.com/[path]
$url = str_replace(home_url(), '', $url);
} else {
// Chop off /path/to/blog
$home_path = parse_url( home_url( '/' ) );
$home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
$url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( $url ) );
}
// Trim leading and lagging slashes
$url = trim($url, '/');
$request = $url;
$post_type_query_vars = array();
foreach ( get_post_types( array() , 'objects' ) as $post_type => $t ) {
if ( ! empty( $t->query_var ) )
$post_type_query_vars[ $t->query_var ] = $post_type;
}
// Look for matches.
$request_match = $request;
foreach ( (array)$rewrite as $match => $query) {
// If the requesting file is the anchor of the match, prepend it
// to the path info.
if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
$request_match = $url . '/' . $request;
if ( preg_match("#^$match#", $request_match, $matches) ) {
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
$page = get_page_by_path( $matches[ $varmatch[1] ] );
if ( ! $page ) {
continue;
}
$post_status_obj = get_post_status_object( $page->post_status );
if ( ! $post_status_obj->public && ! $post_status_obj->protected
&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
continue;
}
}
// Got a match.
// Trim the query of everything up to the '?'.
$query = preg_replace("!^.+\?!", '', $query);
// Substitute the substring matches into the query.
$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
// Filter out non-public query vars
global $wp;
parse_str( $query, $query_vars );
$query = array();
foreach ( (array) $query_vars as $key => $value ) {
if ( in_array( $key, $wp->public_query_vars ) ){
$query[$key] = $value;
if ( isset( $post_type_query_vars[$key] ) ) {
$query['post_type'] = $post_type_query_vars[$key];
$query['name'] = $value;
}
}
}
// Resolve conflicts between posts with numeric slugs and date archive queries.
$query = wp_resolve_numeric_slug_conflicts( $query );
// Do the query
$query = new WP_Query( $query );
if ( ! empty( $query->posts ) && $query->is_singular )
return $query->post->ID;
else
return 0;
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
$wp_version = '4.4-beta4-35717';
$wp_version = '4.4-beta4-35718';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -122,27 +122,41 @@ require( ABSPATH . WPINC . '/class-wp-walker.php' );
require( ABSPATH . WPINC . '/class-wp-ajax-response.php' );
require( ABSPATH . WPINC . '/formatting.php' );
require( ABSPATH . WPINC . '/capabilities.php' );
require( ABSPATH . WPINC . '/class-wp-roles.php' );
require( ABSPATH . WPINC . '/class-wp-role.php' );
require( ABSPATH . WPINC . '/class-wp-user.php' );
require( ABSPATH . WPINC . '/query.php' );
require( ABSPATH . WPINC . '/date.php' );
require( ABSPATH . WPINC . '/theme.php' );
require( ABSPATH . WPINC . '/class-wp-theme.php' );
require( ABSPATH . WPINC . '/template.php' );
require( ABSPATH . WPINC . '/user.php' );
require( ABSPATH . WPINC . '/class-wp-user-query.php' );
require( ABSPATH . WPINC . '/session.php' );
require( ABSPATH . WPINC . '/meta.php' );
require( ABSPATH . WPINC . '/class-wp-meta-query.php' );
require( ABSPATH . WPINC . '/general-template.php' );
require( ABSPATH . WPINC . '/link-template.php' );
require( ABSPATH . WPINC . '/author-template.php' );
require( ABSPATH . WPINC . '/post.php' );
require( ABSPATH . WPINC . '/class-walker-page.php' );
require( ABSPATH . WPINC . '/class-walker-page-dropdown.php' );
require( ABSPATH . WPINC . '/class-wp-post.php' );
require( ABSPATH . WPINC . '/post-template.php' );
require( ABSPATH . WPINC . '/revision.php' );
require( ABSPATH . WPINC . '/post-formats.php' );
require( ABSPATH . WPINC . '/post-thumbnail-template.php' );
require( ABSPATH . WPINC . '/category.php' );
require( ABSPATH . WPINC . '/class-walker-category.php' );
require( ABSPATH . WPINC . '/class-walker-category-dropdown.php' );
require( ABSPATH . WPINC . '/category-template.php' );
require( ABSPATH . WPINC . '/comment.php' );
require( ABSPATH . WPINC . '/class-wp-comment.php' );
require( ABSPATH . WPINC . '/class-wp-comment-query.php' );
require( ABSPATH . WPINC . '/class-walker-comment.php' );
require( ABSPATH . WPINC . '/comment-template.php' );
require( ABSPATH . WPINC . '/rewrite.php' );
require( ABSPATH . WPINC . '/class-wp-rewrite.php' );
require( ABSPATH . WPINC . '/feed.php' );
require( ABSPATH . WPINC . '/bookmark.php' );
require( ABSPATH . WPINC . '/bookmark-template.php' );
@ -151,19 +165,33 @@ require( ABSPATH . WPINC . '/cron.php' );
require( ABSPATH . WPINC . '/deprecated.php' );
require( ABSPATH . WPINC . '/script-loader.php' );
require( ABSPATH . WPINC . '/taxonomy.php' );
require( ABSPATH . WPINC . '/class-wp-term.php' );
require( ABSPATH . WPINC . '/class-wp-tax-query.php' );
require( ABSPATH . WPINC . '/update.php' );
require( ABSPATH . WPINC . '/canonical.php' );
require( ABSPATH . WPINC . '/shortcodes.php' );
require( ABSPATH . WPINC . '/embed.php' );
require( ABSPATH . WPINC . '/class-wp-embed.php' );
require( ABSPATH . WPINC . '/embed-functions.php' );
require( ABSPATH . WPINC . '/class-wp-oembed-controller.php' );
require( ABSPATH . WPINC . '/media.php' );
require( ABSPATH . WPINC . '/http.php' );
require( ABSPATH . WPINC . '/class-http.php' );
require( ABSPATH . WPINC . '/class-wp-http-streams.php' );
require( ABSPATH . WPINC . '/class-wp-http-curl.php' );
require( ABSPATH . WPINC . '/class-wp-http-proxy.php' );
require( ABSPATH . WPINC . '/class-wp-http-cookie.php' );
require( ABSPATH . WPINC . '/class-wp-http-encoding.php' );
require( ABSPATH . WPINC . '/class-wp-http-response.php' );
require( ABSPATH . WPINC . '/widgets.php' );
require( ABSPATH . WPINC . '/class-wp-widget.php' );
require( ABSPATH . WPINC . '/class-wp-widget-factory.php' );
require( ABSPATH . WPINC . '/nav-menu.php' );
require( ABSPATH . WPINC . '/nav-menu-template.php' );
require( ABSPATH . WPINC . '/admin-bar.php' );
require( ABSPATH . WPINC . '/rest-api.php' );
require( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
require( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
require( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
// Load multisite-specific files.
if ( is_multisite() ) {