'' . esc_html( $_value ) . '', '' . esc_html( $key ) . '', '' . esc_html( $check['min'] ) . '', '' . esc_html( $check['max'] ) . '' ); _doing_it_wrong( __CLASS__, $error, '4.1.0' ); $valid = false; } } } // If we already have invalid date messages, don't bother running through checkdate(). if ( ! $valid ) { return $valid; } $day_month_year_error_msg = ''; $day_exists = array_key_exists( 'day', $date_query ) && is_numeric( $date_query['day'] ); $month_exists = array_key_exists( 'month', $date_query ) && is_numeric( $date_query['month'] ); $year_exists = array_key_exists( 'year', $date_query ) && is_numeric( $date_query['year'] ); if ( $day_exists && $month_exists && $year_exists ) { // 1. Checking day, month, year combination. if ( ! wp_checkdate( $date_query['month'], $date_query['day'], $date_query['year'], sprintf( '%s-%s-%s', $date_query['year'], $date_query['month'], $date_query['day'] ) ) ) { /* translators: 1: year, 2: month, 3: day of month */ $day_month_year_error_msg = sprintf( __( 'The following values do not describe a valid date: year %1$s, month %2$s, day %3$s.' ), '' . esc_html( $date_query['year'] ) . '', '' . esc_html( $date_query['month'] ) . '', '' . esc_html( $date_query['day'] ) . '' ); $valid = false; } } elseif ( $day_exists && $month_exists ) { /* * 2. checking day, month combination * We use 2012 because, as a leap year, it's the most permissive. */ if ( ! wp_checkdate( $date_query['month'], $date_query['day'], 2012, sprintf( '2012-%s-%s', $date_query['month'], $date_query['day'] ) ) ) { /* translators: 1: month, 2: day of month */ $day_month_year_error_msg = sprintf( __( 'The following values do not describe a valid date: month %1$s, day %2$s.' ), '' . esc_html( $date_query['month'] ) . '', '' . esc_html( $date_query['day'] ) . '' ); $valid = false; } } if ( ! empty( $day_month_year_error_msg ) ) { _doing_it_wrong( __CLASS__, $day_month_year_error_msg, '4.1.0' ); } return $valid; } /** * Validates a column name parameter. * * Column names without a table prefix (like 'post_date') are checked against a whitelist of * known tables, and then, if found, have a table prefix (such as 'wp_posts.') prepended. * Prefixed column names (such as 'wp_posts.post_date') bypass this whitelist check, * and are only sanitized to remove illegal characters. * * @since 3.7.0 * @access public * * @param string $column The user-supplied column name. * @return string A validated column name value. */ public function validate_column( $column ) { global $wpdb; $valid_columns = array( 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', 'comment_date', 'comment_date_gmt', 'user_registered', ); // Attempt to detect a table prefix. if ( false === strpos( $column, '.' ) ) { /** * Filter the list of valid date query columns. * * @since 3.7.0 * @since 4.1.0 Added 'user_registered' to the default recognized columns. * * @param array $valid_columns An array of valid date query columns. Defaults * are 'post_date', 'post_date_gmt', 'post_modified', * 'post_modified_gmt', 'comment_date', 'comment_date_gmt', * 'user_registered' */ if ( ! in_array( $column, apply_filters( 'date_query_valid_columns', $valid_columns ) ) ) { $column = 'post_date'; } $known_columns = array( $wpdb->posts => array( 'post_date', 'post_date_gmt', 'post_modified', 'post_modified_gmt', ), $wpdb->comments => array( 'comment_date', 'comment_date_gmt', ), $wpdb->users => array( 'user_registered', ), ); // If it's a known column name, add the appropriate table prefix. foreach ( $known_columns as $table_name => $table_columns ) { if ( in_array( $column, $table_columns ) ) { $column = $table_name . '.' . $column; break; } } } // Remove unsafe characters. return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column ); } /** * Generate WHERE clause to be appended to a main query. * * @since 3.7.0 * @access public * * @return string MySQL WHERE clause. */ public function get_sql() { $sql = $this->get_sql_clauses(); $where = $sql['where']; /** * Filter the date query WHERE clause. * * @since 3.7.0 * * @param string $where WHERE clause of the date query. * @param WP_Date_Query $this The WP_Date_Query instance. */ return apply_filters( 'get_date_sql', $where, $this ); } /** * Generate SQL clauses to be appended to a main query. * * Called by the public {@see WP_Date_Query::get_sql()}, this method * is abstracted out to maintain parity with the other Query classes. * * @since 4.1.0 * @access protected * * @return array { * Array containing JOIN and WHERE SQL clauses to append to the main query. * * @type string $join SQL fragment to append to the main JOIN clause. * @type string $where SQL fragment to append to the main WHERE clause. * } */ protected function get_sql_clauses() { $sql = $this->get_sql_for_query( $this->queries ); if ( ! empty( $sql['where'] ) ) { $sql['where'] = ' AND ' . $sql['where']; } return $sql; } /** * Generate SQL clauses for a single query array. * * If nested subqueries are found, this method recurses the tree to * produce the properly nested SQL. * * @since 4.1.0 * @access protected * * @param array $query Query to parse. * @param int $depth Optional. Number of tree levels deep we currently are. * Used to calculate indentation. Default 0. * @return array { * Array containing JOIN and WHERE SQL clauses to append to a single query array. * * @type string $join SQL fragment to append to the main JOIN clause. * @type string $where SQL fragment to append to the main WHERE clause. * } */ protected function get_sql_for_query( $query, $depth = 0 ) { $sql_chunks = array( 'join' => array(), 'where' => array(), ); $sql = array( 'join' => '', 'where' => '', ); $indent = ''; for ( $i = 0; $i < $depth; $i++ ) { $indent .= " "; } foreach ( $query as $key => $clause ) { if ( 'relation' === $key ) { $relation = $query['relation']; } elseif ( is_array( $clause ) ) { // This is a first-order clause. if ( $this->is_first_order_clause( $clause ) ) { $clause_sql = $this->get_sql_for_clause( $clause, $query ); $where_count = count( $clause_sql['where'] ); if ( ! $where_count ) { $sql_chunks['where'][] = ''; } elseif ( 1 === $where_count ) { $sql_chunks['where'][] = $clause_sql['where'][0]; } else { $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; } $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); // This is a subquery, so we recurse. } else { $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); $sql_chunks['where'][] = $clause_sql['where']; $sql_chunks['join'][] = $clause_sql['join']; } } } // Filter to remove empties. $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); if ( empty( $relation ) ) { $relation = 'AND'; } // Filter duplicate JOIN clauses and combine into a single string. if ( ! empty( $sql_chunks['join'] ) ) { $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); } // Generate a single WHERE clause with proper brackets and indentation. if ( ! empty( $sql_chunks['where'] ) ) { $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')'; } return $sql; } /** * Turns a single date clause into pieces for a WHERE clause. * * A wrapper for get_sql_for_clause(), included here for backward * compatibility while retaining the naming convention across Query classes. * * @since 3.7.0 * @access protected * * @param array $query Date query arguments. * @return array { * Array containing JOIN and WHERE SQL clauses to append to the main query. * * @type string $join SQL fragment to append to the main JOIN clause. * @type string $where SQL fragment to append to the main WHERE clause. * } */ protected function get_sql_for_subquery( $query ) { return $this->get_sql_for_clause( $query, '' ); } /** * Turns a first-order date query into SQL for a WHERE clause. * * @since 4.1.0 * @access protected * * @param array $query Date query clause. * @param array $parent_query Parent query of the current date query. * @return array { * Array containing JOIN and WHERE SQL clauses to append to the main query. * * @type string $join SQL fragment to append to the main JOIN clause. * @type string $where SQL fragment to append to the main WHERE clause. * } */ protected function get_sql_for_clause( $query, $parent_query ) { global $wpdb; // The sub-parts of a $where part. $where_parts = array(); $column = ( ! empty( $query['column'] ) ) ? esc_sql( $query['column'] ) : $this->column; $column = $this->validate_column( $column ); $compare = $this->get_compare( $query ); $inclusive = ! empty( $query['inclusive'] ); // Assign greater- and less-than values. $lt = '<'; $gt = '>'; if ( $inclusive ) { $lt .= '='; $gt .= '='; } // Range queries. if ( ! empty( $query['after'] ) ) $where_parts[] = $wpdb->prepare( "$column $gt %s", $this->build_mysql_datetime( $query['after'], ! $inclusive ) ); if ( ! empty( $query['before'] ) ) $where_parts[] = $wpdb->prepare( "$column $lt %s", $this->build_mysql_datetime( $query['before'], $inclusive ) ); // Specific value queries. if ( isset( $query['year'] ) && $value = $this->build_value( $compare, $query['year'] ) ) $where_parts[] = "YEAR( $column ) $compare $value"; if ( isset( $query['month'] ) && $value = $this->build_value( $compare, $query['month'] ) ) { $where_parts[] = "MONTH( $column ) $compare $value"; } elseif ( isset( $query['monthnum'] ) && $value = $this->build_value( $compare, $query['monthnum'] ) ) { $where_parts[] = "MONTH( $column ) $compare $value"; } if ( isset( $query['week'] ) && false !== ( $value = $this->build_value( $compare, $query['week'] ) ) ) { $where_parts[] = _wp_mysql_week( $column ) . " $compare $value"; } elseif ( isset( $query['w'] ) && false !== ( $value = $this->build_value( $compare, $query['w'] ) ) ) { $where_parts[] = _wp_mysql_week( $column ) . " $compare $value"; } if ( isset( $query['dayofyear'] ) && $value = $this->build_value( $compare, $query['dayofyear'] ) ) $where_parts[] = "DAYOFYEAR( $column ) $compare $value"; if ( isset( $query['day'] ) && $value = $this->build_value( $compare, $query['day'] ) ) $where_parts[] = "DAYOFMONTH( $column ) $compare $value"; if ( isset( $query['dayofweek'] ) && $value = $this->build_value( $compare, $query['dayofweek'] ) ) $where_parts[] = "DAYOFWEEK( $column ) $compare $value"; if ( isset( $query['dayofweek_iso'] ) && $value = $this->build_value( $compare, $query['dayofweek_iso'] ) ) $where_parts[] = "WEEKDAY( $column ) + 1 $compare $value"; if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) { // Avoid notices. foreach ( array( 'hour', 'minute', 'second' ) as $unit ) { if ( ! isset( $query[ $unit ] ) ) { $query[ $unit ] = null; } } if ( $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] ) ) { $where_parts[] = $time_query; } } /* * Return an array of 'join' and 'where' for compatibility * with other query classes. */ return array( 'where' => $where_parts, 'join' => array(), ); } /** * Builds and validates a value string based on the comparison operator. * * @since 3.7.0 * @access public * * @param string $compare The compare operator to use * @param string|array $value The value * @return string|false|int The value to be used in SQL or false on error. */ public function build_value( $compare, $value ) { if ( ! isset( $value ) ) return false; switch ( $compare ) { case 'IN': case 'NOT IN': $value = (array) $value; // Remove non-numeric values. $value = array_filter( $value, 'is_numeric' ); if ( empty( $value ) ) { return false; } return '(' . implode( ',', array_map( 'intval', $value ) ) . ')'; case 'BETWEEN': case 'NOT BETWEEN': if ( ! is_array( $value ) || 2 != count( $value ) ) { $value = array( $value, $value ); } else { $value = array_values( $value ); } // If either value is non-numeric, bail. foreach ( $value as $v ) { if ( ! is_numeric( $v ) ) { return false; } } $value = array_map( 'intval', $value ); return $value[0] . ' AND ' . $value[1]; default; if ( ! is_numeric( $value ) ) { return false; } return (int) $value; } } /** * Builds a MySQL format date/time based on some query parameters. * * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can * pass a string that will be run through strtotime(). * * @since 3.7.0 * @access public * * @param string|array $datetime An array of parameters or a strotime() string * @param bool $default_to_max Whether to round up incomplete dates. Supported by values * of $datetime that are arrays, or string values that are a * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i'). * Default: false. * @return string|false A MySQL format date/time or false on failure */ public function build_mysql_datetime( $datetime, $default_to_max = false ) { $now = current_time( 'timestamp' ); if ( ! is_array( $datetime ) ) { /* * Try to parse some common date formats, so we can detect * the level of precision and support the 'inclusive' parameter. */ if ( preg_match( '/^(\d{4})$/', $datetime, $matches ) ) { // Y $datetime = array( 'year' => intval( $matches[1] ), ); } elseif ( preg_match( '/^(\d{4})\-(\d{2})$/', $datetime, $matches ) ) { // Y-m $datetime = array( 'year' => intval( $matches[1] ), 'month' => intval( $matches[2] ), ); } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2})$/', $datetime, $matches ) ) { // Y-m-d $datetime = array( 'year' => intval( $matches[1] ), 'month' => intval( $matches[2] ), 'day' => intval( $matches[3] ), ); } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2})$/', $datetime, $matches ) ) { // Y-m-d H:i $datetime = array( 'year' => intval( $matches[1] ), 'month' => intval( $matches[2] ), 'day' => intval( $matches[3] ), 'hour' => intval( $matches[4] ), 'minute' => intval( $matches[5] ), ); } // If no match is found, we don't support default_to_max. if ( ! is_array( $datetime ) ) { // @todo Timezone issues here possibly return gmdate( 'Y-m-d H:i:s', strtotime( $datetime, $now ) ); } } $datetime = array_map( 'absint', $datetime ); if ( ! isset( $datetime['year'] ) ) $datetime['year'] = gmdate( 'Y', $now ); if ( ! isset( $datetime['month'] ) ) $datetime['month'] = ( $default_to_max ) ? 12 : 1; if ( ! isset( $datetime['day'] ) ) $datetime['day'] = ( $default_to_max ) ? (int) date( 't', mktime( 0, 0, 0, $datetime['month'], 1, $datetime['year'] ) ) : 1; if ( ! isset( $datetime['hour'] ) ) $datetime['hour'] = ( $default_to_max ) ? 23 : 0; if ( ! isset( $datetime['minute'] ) ) $datetime['minute'] = ( $default_to_max ) ? 59 : 0; if ( ! isset( $datetime['second'] ) ) $datetime['second'] = ( $default_to_max ) ? 59 : 0; return sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['minute'], $datetime['second'] ); } /** * Builds a query string for comparing time values (hour, minute, second). * * If just hour, minute, or second is set than a normal comparison will be done. * However if multiple values are passed, a pseudo-decimal time will be created * in order to be able to accurately compare against. * * @since 3.7.0 * @access public * * @param string $column The column to query against. Needs to be pre-validated! * @param string $compare The comparison operator. Needs to be pre-validated! * @param int|null $hour Optional. An hour value (0-23). * @param int|null $minute Optional. A minute value (0-59). * @param int|null $second Optional. A second value (0-59). * @return string|false A query part or false on failure. */ public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) { global $wpdb; // Have to have at least one if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) return false; // Complex combined queries aren't supported for multi-value queries if ( in_array( $compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) { $return = array(); if ( isset( $hour ) && false !== ( $value = $this->build_value( $compare, $hour ) ) ) $return[] = "HOUR( $column ) $compare $value"; if ( isset( $minute ) && false !== ( $value = $this->build_value( $compare, $minute ) ) ) $return[] = "MINUTE( $column ) $compare $value"; if ( isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) ) $return[] = "SECOND( $column ) $compare $value"; return implode( ' AND ', $return ); } // Cases where just one unit is set if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $hour ) ) ) { return "HOUR( $column ) $compare $value"; } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_value( $compare, $minute ) ) ) { return "MINUTE( $column ) $compare $value"; } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) && false !== ( $value = $this->build_value( $compare, $second ) ) ) { return "SECOND( $column ) $compare $value"; } // Single units were already handled. Since hour & second isn't allowed, minute must to be set. if ( ! isset( $minute ) ) return false; $format = $time = ''; // Hour if ( null !== $hour ) { $format .= '%H.'; $time .= sprintf( '%02d', $hour ) . '.'; } else { $format .= '0.'; $time .= '0.'; } // Minute $format .= '%i'; $time .= sprintf( '%02d', $minute ); if ( isset( $second ) ) { $format .= '%s'; $time .= sprintf( '%02d', $second ); } return $wpdb->prepare( "DATE_FORMAT( $column, %s ) $compare %f", $format, $time ); } } } /** This filter is documented in wp-includes/user.php */ $user = apply_filters( 'wp_authenticate_user', $user, $password ); if ( is_wp_error( $user ) ) { return $user; } if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) { return new WP_Error( 'incorrect_password', sprintf( /* translators: %s: email address */ __( 'ERROR: The password you entered for the email address %s is incorrect.' ), '' . $email . '' ) . ' ' . __( 'Lost your password?' ) . '' ); } return $user; } /** * Authenticate the user using the WordPress auth cookie. * * @since 2.8.0 * * @global string $auth_secure_cookie * * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. * @param string $username Username. If not empty, cancels the cookie authentication. * @param string $password Password. If not empty, cancels the cookie authentication. * @return WP_User|WP_Error WP_User on success, WP_Error on failure. */ function wp_authenticate_cookie($user, $username, $password) { if ( $user instanceof WP_User ) { return $user; } if ( empty($username) && empty($password) ) { $user_id = wp_validate_auth_cookie(); if ( $user_id ) return new WP_User($user_id); global $auth_secure_cookie; if ( $auth_secure_cookie ) $auth_cookie = SECURE_AUTH_COOKIE; else $auth_cookie = AUTH_COOKIE; if ( !empty($_COOKIE[$auth_cookie]) ) return new WP_Error('expired_session', __('Please log in again.')); // If the cookie is not set, be silent. } return $user; } /** * For Multisite blogs, check if the authenticated user has been marked as a * spammer, or if the user's primary blog has been marked as spam. * * @since 3.7.0 * * @param WP_User|WP_Error|null $user WP_User or WP_Error object from a previous callback. Default null. * @return WP_User|WP_Error WP_User on success, WP_Error if the user is considered a spammer. */ function wp_authenticate_spam_check( $user ) { if ( $user instanceof WP_User && is_multisite() ) { /** * Filter whether the user has been marked as a spammer. * * @since 3.7.0 * * @param bool $spammed Whether the user is considered a spammer. * @param WP_User $user User to check against. */ $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user ); if ( $spammed ) return new WP_Error( 'spammer_account', __( 'ERROR: Your account has been marked as a spammer.' ) ); } return $user; } /** * Validate the logged-in cookie. * * Checks the logged-in cookie if the previous auth cookie could not be * validated and parsed. * * This is a callback for the determine_current_user filter, rather than API. * * @since 3.9.0 * * @param int|bool $user_id The user ID (or false) as received from the * determine_current_user filter. * @return int|false User ID if validated, false otherwise. If a user ID from * an earlier filter callback is received, that value is returned. */ function wp_validate_logged_in_cookie( $user_id ) { if ( $user_id ) { return $user_id; } if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) ) { return false; } return wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' ); } /** * Number of posts user has written. * * @since 3.0.0 * @since 4.1.0 Added `$post_type` argument. * @since 4.3.0 Added `$public_only` argument. Added the ability to pass an array * of post types to `$post_type`. * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $userid User ID. * @param array|string $post_type Optional. Single post type or array of post types to count the number of posts for. Default 'post'. * @param bool $public_only Optional. Whether to only return counts for public posts. Default false. * @return string Number of posts the user has written in this post type. */ function count_user_posts( $userid, $post_type = 'post', $public_only = false ) { global $wpdb; $where = get_posts_by_author_sql( $post_type, true, $userid, $public_only ); $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" ); /** * Filter the number of posts a user has written. * * @since 2.7.0 * @since 4.1.0 Added `$post_type` argument. * @since 4.3.1 Added `$public_only` argument. * * @param int $count The user's post count. * @param int $userid User ID. * @param string|array $post_type Single post type or array of post types to count the number of posts for. * @param bool $public_only Whether to limit counted posts to public posts. */ return apply_filters( 'get_usernumposts', $count, $userid, $post_type, $public_only ); } /** * Number of posts written by a list of users. * * @since 3.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $users Array of user IDs. * @param string|array $post_type Optional. Single post type or array of post types to check. Defaults to 'post'. * @param bool $public_only Optional. Only return counts for public posts. Defaults to false. * @return array Amount of posts each user has written. */ function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) { global $wpdb; $count = array(); if ( empty( $users ) || ! is_array( $users ) ) return $count; $userlist = implode( ',', array_map( 'absint', $users ) ); $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); foreach ( $result as $row ) { $count[ $row[0] ] = $row[1]; } foreach ( $users as $id ) { if ( ! isset( $count[ $id ] ) ) $count[ $id ] = 0; } return $count; } // // User option functions // /** * Get the current user's ID * * @since MU * * @return int The current user's ID */ function get_current_user_id() { if ( ! function_exists( 'wp_get_current_user' ) ) return 0; $user = wp_get_current_user(); return ( isset( $user->ID ) ? (int) $user->ID : 0 ); } /** * Retrieve user option that can be either per Site or per Network. * * If the user ID is not given, then the current user will be used instead. If * the user ID is given, then the user data will be retrieved. The filter for * the result, will also pass the original option name and finally the user data * object as the third parameter. * * The option will first check for the per site name and then the per Network name. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $option User option name. * @param int $user Optional. User ID. * @param string $deprecated Use get_option() to check for an option in the options table. * @return mixed User option value on success, false on failure. */ function get_user_option( $option, $user = 0, $deprecated = '' ) { global $wpdb; if ( !empty( $deprecated ) ) _deprecated_argument( __FUNCTION__, '3.0' ); if ( empty( $user ) ) $user = get_current_user_id(); if ( ! $user = get_userdata( $user ) ) return false; $prefix = $wpdb->get_blog_prefix(); if ( $user->has_prop( $prefix . $option ) ) // Blog specific $result = $user->get( $prefix . $option ); elseif ( $user->has_prop( $option ) ) // User specific and cross-blog $result = $user->get( $option ); else $result = false; /** * Filter a specific user option value. * * The dynamic portion of the hook name, `$option`, refers to the user option name. * * @since 2.5.0 * * @param mixed $result Value for the user's option. * @param string $option Name of the option being retrieved. * @param WP_User $user WP_User object of the user whose option is being retrieved. */ return apply_filters( "get_user_option_{$option}", $result, $option, $user ); } /** * Update user option with global blog capability. * * User options are just like user metadata except that they have support for * global blog options. If the 'global' parameter is false, which it is by default * it will prepend the WordPress table prefix to the option name. * * Deletes the user option if $newvalue is empty. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID. * @param string $option_name User option name. * @param mixed $newvalue User option value. * @param bool $global Optional. Whether option name is global or blog specific. * Default false (blog specific). * @return int|bool User meta ID if the option didn't exist, true on successful update, * false on failure. */ function update_user_option( $user_id, $option_name, $newvalue, $global = false ) { global $wpdb; if ( !$global ) $option_name = $wpdb->get_blog_prefix() . $option_name; return update_user_meta( $user_id, $option_name, $newvalue ); } /** * Delete user option with global blog capability. * * User options are just like user metadata except that they have support for * global blog options. If the 'global' parameter is false, which it is by default * it will prepend the WordPress table prefix to the option name. * * @since 3.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID * @param string $option_name User option name. * @param bool $global Optional. Whether option name is global or blog specific. * Default false (blog specific). * @return bool True on success, false on failure. */ function delete_user_option( $user_id, $option_name, $global = false ) { global $wpdb; if ( !$global ) $option_name = $wpdb->get_blog_prefix() . $option_name; return delete_user_meta( $user_id, $option_name ); } /** * Retrieve list of users matching criteria. * * @since 3.1.0 * * @see WP_User_Query * * @param array $args Optional. Arguments to retrieve users. See {@see WP_User_Query::prepare_query()} * for more information on accepted arguments. * @return array List of users. */ function get_users( $args = array() ) { $args = wp_parse_args( $args ); $args['count_total'] = false; $user_search = new WP_User_Query($args); return (array) $user_search->get_results(); } /** * Get the blogs a user belongs to. * * @since 3.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $user_id User ID * @param bool $all Whether to retrieve all blogs, or only blogs that are not * marked as deleted, archived, or spam. * @return array A list of the user's blogs. An empty array if the user doesn't exist * or belongs to no blogs. */ function get_blogs_of_user( $user_id, $all = false ) { global $wpdb; $user_id = (int) $user_id; // Logged out users can't have blogs if ( empty( $user_id ) ) return array(); $keys = get_user_meta( $user_id ); if ( empty( $keys ) ) return array(); if ( ! is_multisite() ) { $blog_id = get_current_blog_id(); $blogs = array( $blog_id => new stdClass ); $blogs[ $blog_id ]->userblog_id = $blog_id; $blogs[ $blog_id ]->blogname = get_option('blogname'); $blogs[ $blog_id ]->domain = ''; $blogs[ $blog_id ]->path = ''; $blogs[ $blog_id ]->site_id = 1; $blogs[ $blog_id ]->siteurl = get_option('siteurl'); $blogs[ $blog_id ]->archived = 0; $blogs[ $blog_id ]->spam = 0; $blogs[ $blog_id ]->deleted = 0; return $blogs; } $blogs = array(); if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) { $blog = get_blog_details( 1 ); if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) { $blogs[ 1 ] = (object) array( 'userblog_id' => 1, 'blogname' => $blog->blogname, 'domain' => $blog->domain, 'path' => $blog->path, 'site_id' => $blog->site_id, 'siteurl' => $blog->siteurl, 'archived' => $blog->archived, 'mature' => $blog->mature, 'spam' => $blog->spam, 'deleted' => $blog->deleted, ); } unset( $keys[ $wpdb->base_prefix . 'capabilities' ] ); } $keys = array_keys( $keys ); foreach ( $keys as $key ) { if ( 'capabilities' !== substr( $key, -12 ) ) continue; if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) continue; $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key ); if ( ! is_numeric( $blog_id ) ) continue; $blog_id = (int) $blog_id; $blog = get_blog_details( $blog_id ); if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) { $blogs[ $blog_id ] = (object) array( 'userblog_id' => $blog_id, 'blogname' => $blog->blogname, 'domain' => $blog->domain, 'path' => $blog->path, 'site_id' => $blog->site_id, 'siteurl' => $blog->siteurl, 'archived' => $blog->archived, 'mature' => $blog->mature, 'spam' => $blog->spam, 'deleted' => $blog->deleted, ); } } /** * Filter the list of blogs a user belongs to. * * @since MU * * @param array $blogs An array of blog objects belonging to the user. * @param int $user_id User ID. * @param bool $all Whether the returned blogs array should contain all blogs, including * those marked 'deleted', 'archived', or 'spam'. Default false. */ return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all ); } /** * Find out whether a user is a member of a given blog. * * @since MU 1.1 * * @param int $user_id Optional. The unique ID of the user. Defaults to the current user. * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site. * @return bool */ function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) { global $wpdb; $user_id = (int) $user_id; $blog_id = (int) $blog_id; if ( empty( $user_id ) ) { $user_id = get_current_user_id(); } // Technically not needed, but does save calls to get_blog_details and get_user_meta // in the event that the function is called when a user isn't logged in if ( empty( $user_id ) ) { return false; } else { $user = get_userdata( $user_id ); if ( ! $user instanceof WP_User ) { return false; } } if ( ! is_multisite() ) { return true; } if ( empty( $blog_id ) ) { $blog_id = get_current_blog_id(); } $blog = get_blog_details( $blog_id ); if ( ! $blog || ! isset( $blog->domain ) || $blog->archived || $blog->spam || $blog->deleted ) { return false; } $keys = get_user_meta( $user_id ); if ( empty( $keys ) ) { return false; } // no underscore before capabilities in $base_capabilities_key $base_capabilities_key = $wpdb->base_prefix . 'capabilities'; $site_capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities'; if ( isset( $keys[ $base_capabilities_key ] ) && $blog_id == 1 ) { return true; } if ( isset( $keys[ $site_capabilities_key ] ) ) { return true; } return false; } /** * Add meta data field to a user. * * Post meta data is called "Custom Fields" on the Administration Screens. * * @since 3.0.0 * @link https://codex.wordpress.org/Function_Reference/add_user_meta * * @param int $user_id User ID. * @param string $meta_key Metadata name. * @param mixed $meta_value Metadata value. * @param bool $unique Optional, default is false. Whether the same key should not be added. * @return int|false Meta ID on success, false on failure. */ function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) { return add_metadata('user', $user_id, $meta_key, $meta_value, $unique); } /** * Remove metadata matching criteria from a user. * * You can match based on the key, or key and value. Removing based on key and * value, will keep from removing duplicate metadata with the same key. It also * allows removing all metadata matching key, if needed. * * @since 3.0.0 * @link https://codex.wordpress.org/Function_Reference/delete_user_meta * * @param int $user_id User ID * @param string $meta_key Metadata name. * @param mixed $meta_value Optional. Metadata value. * @return bool True on success, false on failure. */ function delete_user_meta($user_id, $meta_key, $meta_value = '') { return delete_metadata('user', $user_id, $meta_key, $meta_value); } /** * Retrieve user meta field for a user. * * @since 3.0.0 * @link https://codex.wordpress.org/Function_Reference/get_user_meta * * @param int $user_id User ID. * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys. * @param bool $single Whether to return a single value. * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true. */ function get_user_meta($user_id, $key = '', $single = false) { return get_metadata('user', $user_id, $key, $single); } /** * Update user meta field based on user ID. * * Use the $prev_value parameter to differentiate between meta fields with the * same key and user ID. * * If the meta field for the user does not exist, it will be added. * * @since 3.0.0 * @link https://codex.wordpress.org/Function_Reference/update_user_meta * * @param int $user_id User ID. * @param string $meta_key Metadata key. * @param mixed $meta_value Metadata value. * @param mixed $prev_value Optional. Previous value to check before removing. * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure. */ function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') { return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value); } /** * Count number of users who have each of the user roles. * * Assumes there are neither duplicated nor orphaned capabilities meta_values. * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query() * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users. * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257. * * @since 3.0.0 * @since 4.4.0 The number of users with no role is now included in the `none` element. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $strategy 'time' or 'memory' * @return array Includes a grand total and an array of counts indexed by role strings. */ function count_users($strategy = 'time') { global $wpdb; // Initialize $id = get_current_blog_id(); $blog_prefix = $wpdb->get_blog_prefix($id); $result = array(); if ( 'time' == $strategy ) { $avail_roles = wp_roles()->get_names(); // Build a CPU-intensive query that will return concise information. $select_count = array(); foreach ( $avail_roles as $this_role => $name ) { $select_count[] = $wpdb->prepare( "COUNT(NULLIF(`meta_value` LIKE %s, false))", '%' . $wpdb->esc_like( '"' . $this_role . '"' ) . '%'); } $select_count[] = "COUNT(NULLIF(`meta_value` = 'a:0:{}', false))"; $select_count = implode(', ', $select_count); // Add the meta_value index to the selection list, then run the query. $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N ); // Run the previous loop again to associate results with role names. $col = 0; $role_counts = array(); foreach ( $avail_roles as $this_role => $name ) { $count = (int) $row[$col++]; if ($count > 0) { $role_counts[$this_role] = $count; } } $role_counts['none'] = (int) $row[$col++]; // Get the meta_value index from the end of the result set. $total_users = (int) $row[$col]; $result['total_users'] = $total_users; $result['avail_roles'] =& $role_counts; } else { $avail_roles = array( 'none' => 0, ); $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" ); foreach ( $users_of_blog as $caps_meta ) { $b_roles = maybe_unserialize($caps_meta); if ( ! is_array( $b_roles ) ) continue; if ( empty( $b_roles ) ) { $avail_roles['none']++; } foreach ( $b_roles as $b_role => $val ) { if ( isset($avail_roles[$b_role]) ) { $avail_roles[$b_role]++; } else { $avail_roles[$b_role] = 1; } } } $result['total_users'] = count( $users_of_blog ); $result['avail_roles'] =& $avail_roles; } if ( is_multisite() ) { $result['avail_roles']['none'] = 0; } return $result; } // // Private helper functions // /** * Set up global user vars. * * Used by wp_set_current_user() for back compat. Might be deprecated in the future. * * @since 2.0.4 * * @global string $user_login The user username for logging in * @global object $userdata User data. * @global int $user_level The level of the user * @global int $user_ID The ID of the user * @global string $user_email The email address of the user * @global string $user_url The url in the user's profile * @global string $user_identity The display name of the user * * @param int $for_user_id Optional. User ID to set up global data. */ function setup_userdata($for_user_id = '') { global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity; if ( '' == $for_user_id ) $for_user_id = get_current_user_id(); $user = get_userdata( $for_user_id ); if ( ! $user ) { $user_ID = 0; $user_level = 0; $userdata = null; $user_login = $user_email = $user_url = $user_identity = ''; return; } $user_ID = (int) $user->ID; $user_level = (int) $user->user_level; $userdata = $user; $user_login = $user->user_login; $user_email = $user->user_email; $user_url = $user->user_url; $user_identity = $user->display_name; } /** * Create dropdown HTML content of users. * * The content can either be displayed, which it is by default or retrieved by * setting the 'echo' argument. The 'include' and 'exclude' arguments do not * need to be used; all users will be displayed in that case. Only one can be * used, either 'include' or 'exclude', but not both. * * The available arguments are as follows: * * @since 2.3.0 * @since 4.5.0 Added the 'display_name_with_login' value for 'show'. * * @global int $blog_id * * @param array|string $args { * Optional. Array or string of arguments to generate a drop-down of users. * {@see WP_User_Query::prepare_query() for additional available arguments. * * @type string $show_option_all Text to show as the drop-down default (all). * Default empty. * @type string $show_option_none Text to show as the drop-down default when no * users were found. Default empty. * @type int|string $option_none_value Value to use for $show_option_non when no users * were found. Default -1. * @type string $hide_if_only_one_author Whether to skip generating the drop-down * if only one user was found. Default empty. * @type string $orderby Field to order found users by. Accepts user fields. * Default 'display_name'. * @type string $order Whether to order users in ascending or descending * order. Accepts 'ASC' (ascending) or 'DESC' (descending). * Default 'ASC'. * @type array|string $include Array or comma-separated list of user IDs to include. * Default empty. * @type array|string $exclude Array or comma-separated list of user IDs to exclude. * Default empty. * @type bool|int $multi Whether to skip the ID attribute on the 'select' element. * Accepts 1|true or 0|false. Default 0|false. * @type string $show User data to display. If the selected item is empty * then the 'user_login' will be displayed in parentheses. * Accepts any user field, or 'display_name_with_login' to show * the display name with user_login in parentheses. * Default 'display_name'. * @type int|bool $echo Whether to echo or return the drop-down. Accepts 1|true (echo) * or 0|false (return). Default 1|true. * @type int $selected Which user ID should be selected. Default 0. * @type bool $include_selected Whether to always include the selected user ID in the drop- * down. Default false. * @type string $name Name attribute of select element. Default 'user'. * @type string $id ID attribute of the select element. Default is the value of $name. * @type string $class Class attribute of the select element. Default empty. * @type int $blog_id ID of blog (Multisite only). Default is ID of the current blog. * @type string $who Which type of users to query. Accepts only an empty string or * 'authors'. Default empty. * } * @return string String of HTML content. */ function wp_dropdown_users( $args = '' ) { $defaults = array( 'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '', 'orderby' => 'display_name', 'order' => 'ASC', 'include' => '', 'exclude' => '', 'multi' => 0, 'show' => 'display_name', 'echo' => 1, 'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '', 'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false, 'option_none_value' => -1 ); $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0; $r = wp_parse_args( $args, $defaults ); $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) ); $fields = array( 'ID', 'user_login' ); $show = ! empty( $r['show'] ) ? $r['show'] : 'display_name'; if ( 'display_name_with_login' === $show ) { $fields[] = 'display_name'; } else { $fields[] = $show; } $query_args['fields'] = $fields; $show_option_all = $r['show_option_all']; $show_option_none = $r['show_option_none']; $option_none_value = $r['option_none_value']; /** * Filter the query arguments for the user drop-down. * * @since 4.4.0 * * @param array $query_args The query arguments for wp_dropdown_users(). * @param array $r The default arguments for wp_dropdown_users(). */ $query_args = apply_filters( 'wp_dropdown_users_args', $query_args, $r ); $users = get_users( $query_args ); $output = ''; if ( ! empty( $users ) && ( empty( $r['hide_if_only_one_author'] ) || count( $users ) > 1 ) ) { $name = esc_attr( $r['name'] ); if ( $r['multi'] && ! $r['id'] ) { $id = ''; } else { $id = $r['id'] ? " id='" . esc_attr( $r['id'] ) . "'" : " id='$name'"; } $output = ""; } /** * Filter the wp_dropdown_users() HTML output. * * @since 2.3.0 * * @param string $output HTML output generated by wp_dropdown_users(). */ $html = apply_filters( 'wp_dropdown_users', $output ); if ( $r['echo'] ) { echo $html; } return $html; } /** * Sanitize user field based on context. * * Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display' * when calling filters. * * @since 2.3.0 * * @param string $field The user Object field name. * @param mixed $value The user Object value. * @param int $user_id User ID. * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display', * 'attribute' and 'js'. * @return mixed Sanitized value. */ function sanitize_user_field($field, $value, $user_id, $context) { $int_fields = array('ID'); if ( in_array($field, $int_fields) ) $value = (int) $value; if ( 'raw' == $context ) return $value; if ( !is_string($value) && !is_numeric($value) ) return $value; $prefixed = false !== strpos( $field, 'user_' ); if ( 'edit' == $context ) { if ( $prefixed ) { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( "edit_{$field}", $value, $user_id ); } else { /** * Filter a user field value in the 'edit' context. * * The dynamic portion of the hook name, `$field`, refers to the prefixed user * field being filtered, such as 'user_login', 'user_email', 'first_name', etc. * * @since 2.9.0 * * @param mixed $value Value of the prefixed user field. * @param int $user_id User ID. */ $value = apply_filters( "edit_user_{$field}", $value, $user_id ); } if ( 'description' == $field ) $value = esc_html( $value ); // textarea_escaped? else $value = esc_attr($value); } elseif ( 'db' == $context ) { if ( $prefixed ) { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( "pre_{$field}", $value ); } else { /** * Filter the value of a user field in the 'db' context. * * The dynamic portion of the hook name, `$field`, refers to the prefixed user * field being filtered, such as 'user_login', 'user_email', 'first_name', etc. * * @since 2.9.0 * * @param mixed $value Value of the prefixed user field. */ $value = apply_filters( "pre_user_{$field}", $value ); } } else { // Use display filters by default. if ( $prefixed ) { /** This filter is documented in wp-includes/post.php */ $value = apply_filters( $field, $value, $user_id, $context ); } else { /** * Filter the value of a user field in a standard context. * * The dynamic portion of the hook name, `$field`, refers to the prefixed user * field being filtered, such as 'user_login', 'user_email', 'first_name', etc. * * @since 2.9.0 * * @param mixed $value The user object value to sanitize. * @param int $user_id User ID. * @param string $context The context to filter within. */ $value = apply_filters( "user_{$field}", $value, $user_id, $context ); } } if ( 'user_url' == $field ) $value = esc_url($value); if ( 'attribute' == $context ) { $value = esc_attr( $value ); } elseif ( 'js' == $context ) { $value = esc_js( $value ); } return $value; } /** * Update all user caches * * @since 3.0.0 * * @param object|WP_User $user User object to be cached * @return bool|null Returns false on failure. */ function update_user_caches( $user ) { if ( $user instanceof WP_User ) { if ( ! $user->exists() ) { return false; } $user = $user->data; } wp_cache_add($user->ID, $user, 'users'); wp_cache_add($user->user_login, $user->ID, 'userlogins'); wp_cache_add($user->user_email, $user->ID, 'useremail'); wp_cache_add($user->user_nicename, $user->ID, 'userslugs'); } /** * Clean all user caches * * @since 3.0.0 * @since 4.4.0 'clean_user_cache' action was added. * * @param WP_User|int $user User object or ID to be cleaned from the cache */ function clean_user_cache( $user ) { if ( is_numeric( $user ) ) $user = new WP_User( $user ); if ( ! $user->exists() ) return; wp_cache_delete( $user->ID, 'users' ); wp_cache_delete( $user->user_login, 'userlogins' ); wp_cache_delete( $user->user_email, 'useremail' ); wp_cache_delete( $user->user_nicename, 'userslugs' ); /** * Fires immediately after the given user's cache is cleaned. * * @since 4.4.0 * * @param int $user_id User ID. * @param WP_User $user User object. */ do_action( 'clean_user_cache', $user->ID, $user ); } /** * Checks whether the given username exists. * * @since 2.0.0 * * @param string $username Username. * @return int|false The user's ID on success, and false on failure. */ function username_exists( $username ) { if ( $user = get_user_by( 'login', $username ) ) { return $user->ID; } return false; } /** * Checks whether the given email exists. * * @since 2.1.0 * * @param string $email Email. * @return int|false The user's ID on success, and false on failure. */ function email_exists( $email ) { if ( $user = get_user_by( 'email', $email) ) { return $user->ID; } return false; } /** * Checks whether a username is valid. * * @since 2.0.1 * @since 4.4.0 Empty sanitized usernames are now considered invalid * * @param string $username Username. * @return bool Whether username given is valid */ function validate_username( $username ) { $sanitized = sanitize_user( $username, true ); $valid = ( $sanitized == $username && ! empty( $sanitized ) ); /** * Filter whether the provided username is valid or not. * * @since 2.0.1 * * @param bool $valid Whether given username is valid. * @param string $username Username to check. */ return apply_filters( 'validate_username', $valid, $username ); } /** * Insert a user into the database. * * Most of the `$userdata` array fields have filters associated with the values. Exceptions are * 'ID', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', * 'user_registered', and 'role'. The filters have the prefix 'pre_user_' followed by the field * name. An example using 'description' would have the filter called, 'pre_user_description' that * can be hooked into. * * @since 2.0.0 * @since 3.6.0 The `aim`, `jabber`, and `yim` fields were removed as default user contact * methods for new installs. See wp_get_user_contact_methods(). * * @global wpdb $wpdb WordPress database abstraction object. * * @param array|object|WP_User $userdata { * An array, object, or WP_User object of user data arguments. * * @type int $ID User ID. If supplied, the user will be updated. * @type string $user_pass The plain-text user password. * @type string $user_login The user's login username. * @type string $user_nicename The URL-friendly user name. * @type string $user_url The user URL. * @type string $user_email The user email address. * @type string $display_name The user's display name. * Default is the user's username. * @type string $nickname The user's nickname. * Default is the user's username. * @type string $first_name The user's first name. For new users, will be used * to build the first part of the user's display name * if `$display_name` is not specified. * @type string $last_name The user's last name. For new users, will be used * to build the second part of the user's display name * if `$display_name` is not specified. * @type string $description The user's biographical description. * @type string|bool $rich_editing Whether to enable the rich-editor for the user. * False if not empty. * @type string|bool $comment_shortcuts Whether to enable comment moderation keyboard * shortcuts for the user. Default false. * @type string $admin_color Admin color scheme for the user. Default 'fresh'. * @type bool $use_ssl Whether the user should always access the admin over * https. Default false. * @type string $user_registered Date the user registered. Format is 'Y-m-d H:i:s'. * @type string|bool $show_admin_bar_front Whether to display the Admin Bar for the user on the * site's front end. Default true. * @type string $role User's role. * } * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not * be created. */ function wp_insert_user( $userdata ) { global $wpdb; if ( $userdata instanceof stdClass ) { $userdata = get_object_vars( $userdata ); } elseif ( $userdata instanceof WP_User ) { $userdata = $userdata->to_array(); } // Are we updating or creating? if ( ! empty( $userdata['ID'] ) ) { $ID = (int) $userdata['ID']; $update = true; $old_user_data = get_userdata( $ID ); if ( ! $old_user_data ) { return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) ); } // hashed in wp_update_user(), plaintext if called directly $user_pass = ! empty( $userdata['user_pass'] ) ? $userdata['user_pass'] : $old_user_data->user_pass; } else { $update = false; // Hash the password $user_pass = wp_hash_password( $userdata['user_pass'] ); } $sanitized_user_login = sanitize_user( $userdata['user_login'], true ); /** * Filter a username after it has been sanitized. * * This filter is called before the user is created or updated. * * @since 2.0.3 * * @param string $sanitized_user_login Username after it has been sanitized. */ $pre_user_login = apply_filters( 'pre_user_login', $sanitized_user_login ); //Remove any non-printable chars from the login string to see if we have ended up with an empty username $user_login = trim( $pre_user_login ); // user_login must be between 0 and 60 characters. if ( empty( $user_login ) ) { return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') ); } elseif ( mb_strlen( $user_login ) > 60 ) { return new WP_Error( 'user_login_too_long', __( 'Username may not be longer than 60 characters.' ) ); } if ( ! $update && username_exists( $user_login ) ) { return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) ); } /** * Filter the list of blacklisted usernames. * * @since 4.4.0 * * @param array $usernames Array of blacklisted usernames. */ $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); if ( in_array( strtolower( $user_login ), array_map( 'strtolower', $illegal_logins ) ) ) { return new WP_Error( 'invalid_username', __( 'Sorry, that username is not allowed.' ) ); } /* * If a nicename is provided, remove unsafe user characters before using it. * Otherwise build a nicename from the user_login. */ if ( ! empty( $userdata['user_nicename'] ) ) { $user_nicename = sanitize_user( $userdata['user_nicename'], true ); if ( mb_strlen( $user_nicename ) > 50 ) { return new WP_Error( 'user_nicename_too_long', __( 'Nicename may not be longer than 50 characters.' ) ); } } else { $user_nicename = mb_substr( $user_login, 0, 50 ); } $user_nicename = sanitize_title( $user_nicename ); // Store values to save in user meta. $meta = array(); /** * Filter a user's nicename before the user is created or updated. * * @since 2.0.3 * * @param string $user_nicename The user's nicename. */ $user_nicename = apply_filters( 'pre_user_nicename', $user_nicename ); $raw_user_url = empty( $userdata['user_url'] ) ? '' : $userdata['user_url']; /** * Filter a user's URL before the user is created or updated. * * @since 2.0.3 * * @param string $raw_user_url The user's URL. */ $user_url = apply_filters( 'pre_user_url', $raw_user_url ); $raw_user_email = empty( $userdata['user_email'] ) ? '' : $userdata['user_email']; /** * Filter a user's email before the user is created or updated. * * @since 2.0.3 * * @param string $raw_user_email The user's email. */ $user_email = apply_filters( 'pre_user_email', $raw_user_email ); /* * If there is no update, just check for `email_exists`. If there is an update, * check if current email and new email are the same, or not, and check `email_exists` * accordingly. */ if ( ( ! $update || ( ! empty( $old_user_data ) && 0 !== strcasecmp( $user_email, $old_user_data->user_email ) ) ) && ! defined( 'WP_IMPORTING' ) && email_exists( $user_email ) ) { return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) ); } $nickname = empty( $userdata['nickname'] ) ? $user_login : $userdata['nickname']; /** * Filter a user's nickname before the user is created or updated. * * @since 2.0.3 * * @param string $nickname The user's nickname. */ $meta['nickname'] = apply_filters( 'pre_user_nickname', $nickname ); $first_name = empty( $userdata['first_name'] ) ? '' : $userdata['first_name']; /** * Filter a user's first name before the user is created or updated. * * @since 2.0.3 * * @param string $first_name The user's first name. */ $meta['first_name'] = apply_filters( 'pre_user_first_name', $first_name ); $last_name = empty( $userdata['last_name'] ) ? '' : $userdata['last_name']; /** * Filter a user's last name before the user is created or updated. * * @since 2.0.3 * * @param string $last_name The user's last name. */ $meta['last_name'] = apply_filters( 'pre_user_last_name', $last_name ); if ( empty( $userdata['display_name'] ) ) { if ( $update ) { $display_name = $user_login; } elseif ( $meta['first_name'] && $meta['last_name'] ) { /* translators: 1: first name, 2: last name */ $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $meta['first_name'], $meta['last_name'] ); } elseif ( $meta['first_name'] ) { $display_name = $meta['first_name']; } elseif ( $meta['last_name'] ) { $display_name = $meta['last_name']; } else { $display_name = $user_login; } } else { $display_name = $userdata['display_name']; } /** * Filter a user's display name before the user is created or updated. * * @since 2.0.3 * * @param string $display_name The user's display name. */ $display_name = apply_filters( 'pre_user_display_name', $display_name ); $description = empty( $userdata['description'] ) ? '' : $userdata['description']; /** * Filter a user's description before the user is created or updated. * * @since 2.0.3 * * @param string $description The user's description. */ $meta['description'] = apply_filters( 'pre_user_description', $description ); $meta['rich_editing'] = empty( $userdata['rich_editing'] ) ? 'true' : $userdata['rich_editing']; $meta['comment_shortcuts'] = empty( $userdata['comment_shortcuts'] ) || 'false' === $userdata['comment_shortcuts'] ? 'false' : 'true'; $admin_color = empty( $userdata['admin_color'] ) ? 'fresh' : $userdata['admin_color']; $meta['admin_color'] = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $admin_color ); $meta['use_ssl'] = empty( $userdata['use_ssl'] ) ? 0 : $userdata['use_ssl']; $user_registered = empty( $userdata['user_registered'] ) ? gmdate( 'Y-m-d H:i:s' ) : $userdata['user_registered']; $meta['show_admin_bar_front'] = empty( $userdata['show_admin_bar_front'] ) ? 'true' : $userdata['show_admin_bar_front']; $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login)); if ( $user_nicename_check ) { $suffix = 2; while ($user_nicename_check) { // user_nicename allows 50 chars. Subtract one for a hyphen, plus the length of the suffix. $base_length = 49 - mb_strlen( $suffix ); $alt_user_nicename = mb_substr( $user_nicename, 0, $base_length ) . "-$suffix"; $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login)); $suffix++; } $user_nicename = $alt_user_nicename; } $compacted = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' ); $data = wp_unslash( $compacted ); if ( $update ) { if ( $user_email !== $old_user_data->user_email ) { $data['user_activation_key'] = ''; } $wpdb->update( $wpdb->users, $data, compact( 'ID' ) ); $user_id = (int) $ID; } else { $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) ); $user_id = (int) $wpdb->insert_id; } $user = new WP_User( $user_id ); /** * Filter a user's meta values and keys before the user is created or updated. * * Does not include contact methods. These are added using `wp_get_user_contact_methods( $user )`. * * @since 4.4.0 * * @param array $meta { * Default meta values and keys for the user. * * @type string $nickname The user's nickname. Default is the user's username. * @type string $first_name The user's first name. * @type string $last_name The user's last name. * @type string $description The user's description. * @type bool $rich_editing Whether to enable the rich-editor for the user. False if not empty. * @type bool $comment_shortcuts Whether to enable keyboard shortcuts for the user. Default false. * @type string $admin_color The color scheme for a user's admin screen. Default 'fresh'. * @type int|bool $use_ssl Whether to force SSL on the user's admin area. 0|false if SSL is * not forced. * @type bool $show_admin_bar_front Whether to show the admin bar on the front end for the user. * Default true. * } * @param WP_User $user User object. * @param bool $update Whether the user is being updated rather than created. */ $meta = apply_filters( 'insert_user_meta', $meta, $user, $update ); // Update user meta. foreach ( $meta as $key => $value ) { update_user_meta( $user_id, $key, $value ); } foreach ( wp_get_user_contact_methods( $user ) as $key => $value ) { if ( isset( $userdata[ $key ] ) ) { update_user_meta( $user_id, $key, $userdata[ $key ] ); } } if ( isset( $userdata['role'] ) ) { $user->set_role( $userdata['role'] ); } elseif ( ! $update ) { $user->set_role(get_option('default_role')); } wp_cache_delete( $user_id, 'users' ); wp_cache_delete( $user_login, 'userlogins' ); if ( $update ) { /** * Fires immediately after an existing user is updated. * * @since 2.0.0 * * @param int $user_id User ID. * @param object $old_user_data Object containing user's data prior to update. */ do_action( 'profile_update', $user_id, $old_user_data ); } else { /** * Fires immediately after a new user is registered. * * @since 1.5.0 * * @param int $user_id User ID. */ do_action( 'user_register', $user_id ); } return $user_id; } /** * Update a user in the database. * * It is possible to update a user's password by specifying the 'user_pass' * value in the $userdata parameter array. * * If current user's password is being updated, then the cookies will be * cleared. * * @since 2.0.0 * * @see wp_insert_user() For what fields can be set in $userdata. * * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User. * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated. */ function wp_update_user($userdata) { if ( $userdata instanceof stdClass ) { $userdata = get_object_vars( $userdata ); } elseif ( $userdata instanceof WP_User ) { $userdata = $userdata->to_array(); } $ID = isset( $userdata['ID'] ) ? (int) $userdata['ID'] : 0; if ( ! $ID ) { return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) ); } // First, get all of the original fields $user_obj = get_userdata( $ID ); if ( ! $user_obj ) { return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) ); } $user = $user_obj->to_array(); // Add additional custom fields foreach ( _get_additional_user_keys( $user_obj ) as $key ) { $user[ $key ] = get_user_meta( $ID, $key, true ); } // Escape data pulled from DB. $user = add_magic_quotes( $user ); if ( ! empty( $userdata['user_pass'] ) && $userdata['user_pass'] !== $user_obj->user_pass ) { // If password is changing, hash it now $plaintext_pass = $userdata['user_pass']; $userdata['user_pass'] = wp_hash_password( $userdata['user_pass'] ); /** * Filter whether to send the password change email. * * @since 4.3.0 * * @see wp_insert_user() For `$user` and `$userdata` fields. * * @param bool $send Whether to send the email. * @param array $user The original user array. * @param array $userdata The updated user array. * */ $send_password_change_email = apply_filters( 'send_password_change_email', true, $user, $userdata ); } if ( isset( $userdata['user_email'] ) && $user['user_email'] !== $userdata['user_email'] ) { /** * Filter whether to send the email change email. * * @since 4.3.0 * * @see wp_insert_user() For `$user` and `$userdata` fields. * * @param bool $send Whether to send the email. * @param array $user The original user array. * @param array $userdata The updated user array. * */ $send_email_change_email = apply_filters( 'send_email_change_email', true, $user, $userdata ); } wp_cache_delete( $user['user_email'], 'useremail' ); wp_cache_delete( $user['user_nicename'], 'userslugs' ); // Merge old and new fields with new fields overwriting old ones. $userdata = array_merge( $user, $userdata ); $user_id = wp_insert_user( $userdata ); if ( ! is_wp_error( $user_id ) ) { $blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); if ( ! empty( $send_password_change_email ) ) { /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */ $pass_change_text = __( 'Hi ###USERNAME###, This notice confirms that your password was changed on ###SITENAME###. If you did not change your password, please contact the Site Administrator at ###ADMIN_EMAIL### This email has been sent to ###EMAIL### Regards, All at ###SITENAME### ###SITEURL###' ); $pass_change_email = array( 'to' => $user['user_email'], 'subject' => __( '[%s] Notice of Password Change' ), 'message' => $pass_change_text, 'headers' => '', ); /** * Filter the contents of the email sent when the user's password is changed. * * @since 4.3.0 * * @param array $pass_change_email { * Used to build wp_mail(). * @type string $to The intended recipients. Add emails in a comma separated string. * @type string $subject The subject of the email. * @type string $message The content of the email. * The following strings have a special meaning and will get replaced dynamically: * - ###USERNAME### The current user's username. * - ###ADMIN_EMAIL### The admin email in case this was unexpected. * - ###EMAIL### The old email. * - ###SITENAME### The name of the site. * - ###SITEURL### The URL to the site. * @type string $headers Headers. Add headers in a newline (\r\n) separated string. * } * @param array $user The original user array. * @param array $userdata The updated user array. * */ $pass_change_email = apply_filters( 'password_change_email', $pass_change_email, $user, $userdata ); $pass_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $pass_change_email['message'] ); $pass_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $pass_change_email['message'] ); $pass_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $pass_change_email['message'] ); $pass_change_email['message'] = str_replace( '###SITENAME###', $blog_name, $pass_change_email['message'] ); $pass_change_email['message'] = str_replace( '###SITEURL###', home_url(), $pass_change_email['message'] ); wp_mail( $pass_change_email['to'], sprintf( $pass_change_email['subject'], $blog_name ), $pass_change_email['message'], $pass_change_email['headers'] ); } if ( ! empty( $send_email_change_email ) ) { /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */ $email_change_text = __( 'Hi ###USERNAME###, This notice confirms that your email was changed on ###SITENAME###. If you did not change your email, please contact the Site Administrator at ###ADMIN_EMAIL### This email has been sent to ###EMAIL### Regards, All at ###SITENAME### ###SITEURL###' ); $email_change_email = array( 'to' => $user['user_email'], 'subject' => __( '[%s] Notice of Email Change' ), 'message' => $email_change_text, 'headers' => '', ); /** * Filter the contents of the email sent when the user's email is changed. * * @since 4.3.0 * * @param array $email_change_email { * Used to build wp_mail(). * @type string $to The intended recipients. * @type string $subject The subject of the email. * @type string $message The content of the email. * The following strings have a special meaning and will get replaced dynamically: * - ###USERNAME### The current user's username. * - ###ADMIN_EMAIL### The admin email in case this was unexpected. * - ###EMAIL### The old email. * - ###SITENAME### The name of the site. * - ###SITEURL### The URL to the site. * @type string $headers Headers. * } * @param array $user The original user array. * @param array $userdata The updated user array. */ $email_change_email = apply_filters( 'email_change_email', $email_change_email, $user, $userdata ); $email_change_email['message'] = str_replace( '###USERNAME###', $user['user_login'], $email_change_email['message'] ); $email_change_email['message'] = str_replace( '###ADMIN_EMAIL###', get_option( 'admin_email' ), $email_change_email['message'] ); $email_change_email['message'] = str_replace( '###EMAIL###', $user['user_email'], $email_change_email['message'] ); $email_change_email['message'] = str_replace( '###SITENAME###', $blog_name, $email_change_email['message'] ); $email_change_email['message'] = str_replace( '###SITEURL###', home_url(), $email_change_email['message'] ); wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] ); } } // Update the cookies if the password changed. $current_user = wp_get_current_user(); if ( $current_user->ID == $ID ) { if ( isset($plaintext_pass) ) { wp_clear_auth_cookie(); // Here we calculate the expiration length of the current auth cookie and compare it to the default expiration. // If it's greater than this, then we know the user checked 'Remember Me' when they logged in. $logged_in_cookie = wp_parse_auth_cookie( '', 'logged_in' ); /** This filter is documented in wp-includes/pluggable.php */ $default_cookie_life = apply_filters( 'auth_cookie_expiration', ( 2 * DAY_IN_SECONDS ), $ID, false ); $remember = ( ( $logged_in_cookie['expiration'] - time() ) > $default_cookie_life ); wp_set_auth_cookie( $ID, $remember ); } } return $user_id; } /** * A simpler way of inserting a user into the database. * * Creates a new user with just the username, password, and email. For more * complex user creation use {@see wp_insert_user()} to specify more information. * * @since 2.0.0 * @see wp_insert_user() More complete way to create a new user * * @param string $username The user's username. * @param string $password The user's password. * @param string $email Optional. The user's email. Default empty. * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not * be created. */ function wp_create_user($username, $password, $email = '') { $user_login = wp_slash( $username ); $user_email = wp_slash( $email ); $user_pass = $password; $userdata = compact('user_login', 'user_email', 'user_pass'); return wp_insert_user($userdata); } /** * Returns a list of meta keys to be (maybe) populated in wp_update_user(). * * The list of keys returned via this function are dependent on the presence * of those keys in the user meta data to be set. * * @since 3.3.0 * @access private * * @param WP_User $user WP_User instance. * @return array List of user keys to be populated in wp_update_user(). */ function _get_additional_user_keys( $user ) { $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' ); return array_merge( $keys, array_keys( wp_get_user_contact_methods( $user ) ) ); } /** * Set up the user contact methods. * * Default contact methods were removed in 3.6. A filter dictates contact methods. * * @since 3.7.0 * * @param WP_User $user Optional. WP_User object. * @return array Array of contact methods and their labels. */ function wp_get_user_contact_methods( $user = null ) { $methods = array(); if ( get_site_option( 'initial_db_version' ) < 23588 ) { $methods = array( 'aim' => __( 'AIM' ), 'yim' => __( 'Yahoo IM' ), 'jabber' => __( 'Jabber / Google Talk' ) ); } /** * Filter the user contact methods. * * @since 2.9.0 * * @param array $methods Array of contact methods and their labels. * @param WP_User $user WP_User object. */ return apply_filters( 'user_contactmethods', $methods, $user ); } /** * The old private function for setting up user contact methods. * * Use wp_get_user_contact_methods() instead. * * @since 2.9.0 * @access private * * @param WP_User $user Optional. WP_User object. Default null. * @return array Array of contact methods and their labels. */ function _wp_get_user_contactmethods( $user = null ) { return wp_get_user_contact_methods( $user ); } /** * Gets the text suggesting how to create strong passwords. * * @since 4.1.0 * * @return string The password hint text. */ function wp_get_password_hint() { $hint = __( 'Hint: The password should be at least twelve characters long. To make it stronger, use upper and lower case letters, numbers, and symbols like ! " ? $ % ^ & ).' ); /** * Filter the text describing the site's password complexity policy. * * @since 4.1.0 * * @param string $hint The password hint text. */ return apply_filters( 'password_hint', $hint ); } /** * Creates, stores, then returns a password reset key for user. * * @since 4.4.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global PasswordHash $wp_hasher Portable PHP password hashing framework. * * @param WP_User $user User to retrieve password reset key for. * * @return string|WP_Error Password reset key on success. WP_Error on error. */ function get_password_reset_key( $user ) { global $wpdb, $wp_hasher; /** * Fires before a new password is retrieved. * * @since 1.5.0 * @deprecated 1.5.1 Misspelled. Use 'retrieve_password' hook instead. * * @param string $user_login The user login name. */ do_action( 'retreive_password', $user->user_login ); /** * Fires before a new password is retrieved. * * @since 1.5.1 * * @param string $user_login The user login name. */ do_action( 'retrieve_password', $user->user_login ); /** * Filter whether to allow a password to be reset. * * @since 2.7.0 * * @param bool $allow Whether to allow the password to be reset. Default true. * @param int $user_data->ID The ID of the user attempting to reset a password. */ $allow = apply_filters( 'allow_password_reset', true, $user->ID ); if ( ! $allow ) { return new WP_Error( 'no_password_reset', __( 'Password reset is not allowed for this user' ) ); } elseif ( is_wp_error( $allow ) ) { return $allow; } // Generate something random for a password reset key. $key = wp_generate_password( 20, false ); /** * Fires when a password reset key is generated. * * @since 2.5.0 * * @param string $user_login The username for the user. * @param string $key The generated password reset key. */ do_action( 'retrieve_password_key', $user->user_login, $key ); // Now insert the key, hashed, into the DB. if ( empty( $wp_hasher ) ) { require_once ABSPATH . WPINC . '/class-phpass.php'; $wp_hasher = new PasswordHash( 8, true ); } $hashed = time() . ':' . $wp_hasher->HashPassword( $key ); $key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) ); if ( false === $key_saved ) { return new WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) ); } return $key; } /** * Retrieves a user row based on password reset key and login * * A key is considered 'expired' if it exactly matches the value of the * user_activation_key field, rather than being matched after going through the * hashing process. This field is now hashed; old values are no longer accepted * but have a different WP_Error code so good user feedback can be provided. * * @since 3.1.0 * * @global wpdb $wpdb WordPress database object for queries. * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance. * * @param string $key Hash to validate sending user's password. * @param string $login The user login. * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys. */ function check_password_reset_key($key, $login) { global $wpdb, $wp_hasher; $key = preg_replace('/[^a-z0-9]/i', '', $key); if ( empty( $key ) || !is_string( $key ) ) return new WP_Error('invalid_key', __('Invalid key')); if ( empty($login) || !is_string($login) ) return new WP_Error('invalid_key', __('Invalid key')); $row = $wpdb->get_row( $wpdb->prepare( "SELECT ID, user_activation_key FROM $wpdb->users WHERE user_login = %s", $login ) ); if ( ! $row ) return new WP_Error('invalid_key', __('Invalid key')); if ( empty( $wp_hasher ) ) { require_once ABSPATH . WPINC . '/class-phpass.php'; $wp_hasher = new PasswordHash( 8, true ); } /** * Filter the expiration time of password reset keys. * * @since 4.3.0 * * @param int $expiration The expiration time in seconds. */ $expiration_duration = apply_filters( 'password_reset_expiration', DAY_IN_SECONDS ); if ( false !== strpos( $row->user_activation_key, ':' ) ) { list( $pass_request_time, $pass_key ) = explode( ':', $row->user_activation_key, 2 ); $expiration_time = $pass_request_time + $expiration_duration; } else { $pass_key = $row->user_activation_key; $expiration_time = false; } if ( ! $pass_key ) { return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); } $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key ); if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) { return get_userdata( $row->ID ); } elseif ( $hash_is_correct && $expiration_time ) { // Key has an expiration time that's passed return new WP_Error( 'expired_key', __( 'Invalid key' ) ); } if ( hash_equals( $row->user_activation_key, $key ) || ( $hash_is_correct && ! $expiration_time ) ) { $return = new WP_Error( 'expired_key', __( 'Invalid key' ) ); $user_id = $row->ID; /** * Filter the return value of check_password_reset_key() when an * old-style key is used. * * @since 3.7.0 Previously plain-text keys were stored in the database. * @since 4.3.0 Previously key hashes were stored without an expiration time. * * @param WP_Error $return A WP_Error object denoting an expired key. * Return a WP_User object to validate the key. * @param int $user_id The matched user ID. */ return apply_filters( 'password_reset_key_expired', $return, $user_id ); } return new WP_Error( 'invalid_key', __( 'Invalid key' ) ); } /** * Handles resetting the user's password. * * @since 2.5.0 * * @param object $user The user * @param string $new_pass New password for the user in plaintext */ function reset_password( $user, $new_pass ) { /** * Fires before the user's password is reset. * * @since 1.5.0 * * @param object $user The user. * @param string $new_pass New user password. */ do_action( 'password_reset', $user, $new_pass ); wp_set_password( $new_pass, $user->ID ); update_user_option( $user->ID, 'default_password_nag', false, true ); /** * Fires after the user's password is reset. * * @since 4.4.0 * * @param object $user The user. * @param string $new_pass New user password. */ do_action( 'after_password_reset', $user, $new_pass ); } /** * Handles registering a new user. * * @since 2.5.0 * * @param string $user_login User's username for logging in * @param string $user_email User's email address to send password and add * @return int|WP_Error Either user's ID or error on failure. */ function register_new_user( $user_login, $user_email ) { $errors = new WP_Error(); $sanitized_user_login = sanitize_user( $user_login ); /** * Filter the email address of a user being registered. * * @since 2.1.0 * * @param string $user_email The email address of the new user. */ $user_email = apply_filters( 'user_registration_email', $user_email ); // Check the username if ( $sanitized_user_login == '' ) { $errors->add( 'empty_username', __( 'ERROR: Please enter a username.' ) ); } elseif ( ! validate_username( $user_login ) ) { $errors->add( 'invalid_username', __( 'ERROR: This username is invalid because it uses illegal characters. Please enter a valid username.' ) ); $sanitized_user_login = ''; } elseif ( username_exists( $sanitized_user_login ) ) { $errors->add( 'username_exists', __( 'ERROR: This username is already registered. Please choose another one.' ) ); } else { /** This filter is documented in wp-includes/user.php */ $illegal_user_logins = array_map( 'strtolower', (array) apply_filters( 'illegal_user_logins', array() ) ); if ( in_array( strtolower( $sanitized_user_login ), $illegal_user_logins ) ) { $errors->add( 'invalid_username', __( 'ERROR: Sorry, that username is not allowed.' ) ); } } // Check the email address if ( $user_email == '' ) { $errors->add( 'empty_email', __( 'ERROR: Please type your email address.' ) ); } elseif ( ! is_email( $user_email ) ) { $errors->add( 'invalid_email', __( 'ERROR: The email address isn’t correct.' ) ); $user_email = ''; } elseif ( email_exists( $user_email ) ) { $errors->add( 'email_exists', __( 'ERROR: This email is already registered, please choose another one.' ) ); } /** * Fires when submitting registration form data, before the user is created. * * @since 2.1.0 * * @param string $sanitized_user_login The submitted username after being sanitized. * @param string $user_email The submitted email. * @param WP_Error $errors Contains any errors with submitted username and email, * e.g., an empty field, an invalid username or email, * or an existing username or email. */ do_action( 'register_post', $sanitized_user_login, $user_email, $errors ); /** * Filter the errors encountered when a new user is being registered. * * The filtered WP_Error object may, for example, contain errors for an invalid * or existing username or email address. A WP_Error object should always returned, * but may or may not contain errors. * * If any errors are present in $errors, this will abort the user's registration. * * @since 2.1.0 * * @param WP_Error $errors A WP_Error object containing any errors encountered * during registration. * @param string $sanitized_user_login User's username after it has been sanitized. * @param string $user_email User's email. */ $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email ); if ( $errors->get_error_code() ) return $errors; $user_pass = wp_generate_password( 12, false ); $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email ); if ( ! $user_id || is_wp_error( $user_id ) ) { $errors->add( 'registerfail', sprintf( __( 'ERROR: Couldn’t register you… please contact the webmaster !' ), get_option( 'admin_email' ) ) ); return $errors; } update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag. /** * Fires after a new user registration has been recorded. * * @since 4.4.0 * * @param int $user_id ID of the newly registered user. */ do_action( 'register_new_user', $user_id ); return $user_id; } /** * Initiate email notifications related to the creation of new users. * * Notifications are sent both to the site admin and to the newly created user. * * @since 4.4.0 * * @param int $user_id ID of the newly created user. * @param string $notify Optional. Type of notification that should happen. Accepts 'admin' or an empty string * (admin only), or 'both' (admin and user). Default 'both'. */ function wp_send_new_user_notifications( $user_id, $notify = 'both' ) { wp_new_user_notification( $user_id, null, $notify ); } /** * Retrieve the current session token from the logged_in cookie. * * @since 4.0.0 * * @return string Token. */ function wp_get_session_token() { $cookie = wp_parse_auth_cookie( '', 'logged_in' ); return ! empty( $cookie['token'] ) ? $cookie['token'] : ''; } /** * Retrieve a list of sessions for the current user. * * @since 4.0.0 * @return array Array of sessions. */ function wp_get_all_sessions() { $manager = WP_Session_Tokens::get_instance( get_current_user_id() ); return $manager->get_all(); } /** * Remove the current session token from the database. * * @since 4.0.0 */ function wp_destroy_current_session() { $token = wp_get_session_token(); if ( $token ) { $manager = WP_Session_Tokens::get_instance( get_current_user_id() ); $manager->destroy( $token ); } } /** * Remove all but the current session token for the current user for the database. * * @since 4.0.0 */ function wp_destroy_other_sessions() { $token = wp_get_session_token(); if ( $token ) { $manager = WP_Session_Tokens::get_instance( get_current_user_id() ); $manager->destroy_others( $token ); } } /** * Remove all session tokens for the current user from the database. * * @since 4.0.0 */ function wp_destroy_all_sessions() { $manager = WP_Session_Tokens::get_instance( get_current_user_id() ); $manager->destroy_all(); } /** * Get the user IDs of all users with no role on this site. * * This function returns an empty array when used on Multisite. * * @since 4.4.0 * * @return array Array of user IDs. */ function wp_get_users_with_no_role() { global $wpdb; if ( is_multisite() ) { return array(); } $prefix = $wpdb->get_blog_prefix(); $regex = implode( '|', wp_roles()->get_names() ); $regex = preg_replace( '/[^a-zA-Z_\|-]/', '', $regex ); $users = $wpdb->get_col( $wpdb->prepare( " SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '{$prefix}capabilities' AND meta_value NOT REGEXP %s ", $regex ) ); return $users; } /** * Retrieves the current user object. * * Will set the current user, if the current user is not set. The current user * will be set to the logged-in person. If no user is logged-in, then it will * set the current user to 0, which is invalid and won't have any permissions. * * This function is used by the pluggable functions wp_get_current_user() and * get_currentuserinfo(), the latter of which is deprecated but used for backward * compatibility. * * @since 4.5.0 * @access private * * @see wp_get_current_user() * @global WP_User $current_user Checks if the current user is set. * * @return WP_User Current WP_User instance. */ function _wp_get_current_user() { global $current_user; if ( ! empty( $current_user ) ) { if ( $current_user instanceof WP_User ) { return $current_user; } // Upgrade stdClass to WP_User if ( is_object( $current_user ) && isset( $current_user->ID ) ) { $cur_id = $current_user->ID; $current_user = null; wp_set_current_user( $cur_id ); return $current_user; } // $current_user has a junk value. Force to WP_User with ID 0. $current_user = null; wp_set_current_user( 0 ); return $current_user; } if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) { wp_set_current_user( 0 ); return $current_user; } /** * Filter the current user. * * The default filters use this to determine the current user from the * request's cookies, if available. * * Returning a value of false will effectively short-circuit setting * the current user. * * @since 3.9.0 * * @param int|bool $user_id User ID if one has been determined, false otherwise. */ $user_id = apply_filters( 'determine_current_user', false ); if ( ! $user_id ) { wp_set_current_user( 0 ); return $current_user; } wp_set_current_user( $user_id ); return $current_user; } a_key = %s AND $column = %d", $meta_key, $object_id ) ); if ( empty( $meta_ids ) ) { return add_metadata( $meta_type, $object_id, $raw_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 ) { /** * 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 ) { /** * 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 ) { if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) { $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s AND meta_value = %s", $meta_key, $meta_value ) ); } else { $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.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.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.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.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.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.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.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; } /** * Retrieves the queue for lazy-loading metadata. * * @since 4.5.0 * * @return WP_Metadata_Lazyloader $lazyloader Metadata lazyloader queue. */ function wp_metadata_lazyloader() { static $wp_metadata_lazyloader; if ( null === $wp_metadata_lazyloader ) { $wp_metadata_lazyloader = new WP_Metadata_Lazyloader(); } return $wp_metadata_lazyloader; } /** * 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 ); } 'wp-login.php', 'login_post' ) ) . '" method="post"> ' . $login_form_top . '

' . $login_form_middle . ' ' . ( $args['remember'] ? '

' : '' ) . '

' . $login_form_bottom . ' '; if ( $args['echo'] ) echo $form; else return $form; } /** * Returns the URL that allows the user to retrieve the lost password * * @since 2.8.0 * * @param string $redirect Path to redirect to on login. * @return string Lost password URL. */ function wp_lostpassword_url( $redirect = '' ) { $args = array( 'action' => 'lostpassword' ); if ( !empty($redirect) ) { $args['redirect_to'] = $redirect; } $lostpassword_url = add_query_arg( $args, network_site_url('wp-login.php', 'login') ); /** * Filter the Lost Password URL. * * @since 2.8.0 * * @param string $lostpassword_url The lost password page URL. * @param string $redirect The path to redirect to on login. */ return apply_filters( 'lostpassword_url', $lostpassword_url, $redirect ); } /** * Display the Registration or Admin link. * * Display a link which allows the user to navigate to the registration page if * not logged in and registration is enabled or to the dashboard if logged in. * * @since 1.5.0 * * @param string $before Text to output before the link. Default `
  • `. * @param string $after Text to output after the link. Default `
  • `. * @param bool $echo Default to echo and not return the link. * @return string|void String when retrieving. */ function wp_register( $before = '
  • ', $after = '
  • ', $echo = true ) { if ( ! is_user_logged_in() ) { if ( get_option('users_can_register') ) $link = $before . '' . __('Register') . '' . $after; else $link = ''; } elseif ( current_user_can( 'read' ) ) { $link = $before . '' . __('Site Admin') . '' . $after; } else { $link = ''; } /** * Filter the HTML link to the Registration or Admin page. * * Users are sent to the admin page if logged-in, or the registration page * if enabled and logged-out. * * @since 1.5.0 * * @param string $link The HTML code for the link to the Registration or Admin page. */ $link = apply_filters( 'register', $link ); if ( $echo ) { echo $link; } else { return $link; } } /** * Theme container function for the 'wp_meta' action. * * The 'wp_meta' action can have several purposes, depending on how you use it, * but one purpose might have been to allow for theme switching. * * @since 1.5.0 * * @link https://core.trac.wordpress.org/ticket/1458 Explanation of 'wp_meta' action. */ function wp_meta() { /** * Fires before displaying echoed content in the sidebar. * * @since 1.5.0 */ do_action( 'wp_meta' ); } /** * Displays information about the current site. * * @since 0.71 * * @see get_bloginfo() For possible `$show` values * * @param string $show Optional. Site information to display. Default empty. */ function bloginfo( $show = '' ) { echo get_bloginfo( $show, 'display' ); } /** * Retrieves information about the current site. * * Possible values for `$show` include: * * - 'name' - Site title (set in Settings > General) * - 'description' - Site tagline (set in Settings > General) * - 'wpurl' - The WordPress address (URL) (set in Settings > General) * - 'url' - The Site address (URL) (set in Settings > General) * - 'admin_email' - Admin email (set in Settings > General) * - 'charset' - The "Encoding for pages and feeds" (set in Settings > Reading) * - 'version' - The current WordPress version * - 'html_type' - The content-type (default: "text/html"). Themes and plugins * can override the default value using the {@see 'pre_option_html_type'} filter * - 'text_direction' - The text direction determined by the site's language. is_rtl() * should be used instead * - 'language' - Language code for the current site * - 'stylesheet_url' - URL to the stylesheet for the active theme. An active child theme * will take precedence over this value * - 'stylesheet_directory' - Directory path for the active theme. An active child theme * will take precedence over this value * - 'template_url' / 'template_directory' - URL of the active theme's directory. An active * child theme will NOT take precedence over this value * - 'pingback_url' - The pingback XML-RPC file URL (xmlrpc.php) * - 'atom_url' - The Atom feed URL (/feed/atom) * - 'rdf_url' - The RDF/RSS 1.0 feed URL (/feed/rfd) * - 'rss_url' - The RSS 0.92 feed URL (/feed/rss) * - 'rss2_url' - The RSS 2.0 feed URL (/feed) * - 'comments_atom_url' - The comments Atom feed URL (/comments/feed) * - 'comments_rss2_url' - The comments RSS 2.0 feed URL (/comments/feed) * * Some `$show` values are deprecated and will be removed in future versions. * These options will trigger the _deprecated_argument() function. * * Deprecated arguments include: * * - 'siteurl' - Use 'url' instead * - 'home' - Use 'url' instead * * @since 0.71 * * @global string $wp_version * * @param string $show Optional. Site info to retrieve. Default empty (site name). * @param string $filter Optional. How to filter what is retrieved. Default 'raw'. * @return string Mostly string values, might be empty. */ function get_bloginfo( $show = '', $filter = 'raw' ) { switch( $show ) { case 'home' : // DEPRECATED case 'siteurl' : // DEPRECATED _deprecated_argument( __FUNCTION__, '2.2', sprintf( /* translators: 1: 'siteurl'/'home' argument, 2: bloginfo() function name, 3: 'url' argument */ __( 'The %1$s option is deprecated for the family of %2$s functions. Use the %3$s option instead.' ), '' . $show . '', 'bloginfo()', 'url' ) ); case 'url' : $output = home_url(); break; case 'wpurl' : $output = site_url(); break; case 'description': $output = get_option('blogdescription'); break; case 'rdf_url': $output = get_feed_link('rdf'); break; case 'rss_url': $output = get_feed_link('rss'); break; case 'rss2_url': $output = get_feed_link('rss2'); break; case 'atom_url': $output = get_feed_link('atom'); break; case 'comments_atom_url': $output = get_feed_link('comments_atom'); break; case 'comments_rss2_url': $output = get_feed_link('comments_rss2'); break; case 'pingback_url': $output = site_url( 'xmlrpc.php' ); break; case 'stylesheet_url': $output = get_stylesheet_uri(); break; case 'stylesheet_directory': $output = get_stylesheet_directory_uri(); break; case 'template_directory': case 'template_url': $output = get_template_directory_uri(); break; case 'admin_email': $output = get_option('admin_email'); break; case 'charset': $output = get_option('blog_charset'); if ('' == $output) $output = 'UTF-8'; break; case 'html_type' : $output = get_option('html_type'); break; case 'version': global $wp_version; $output = $wp_version; break; case 'language': /* translators: Translate this to the correct language tag for your locale, * see https://www.w3.org/International/articles/language-tags/ for reference. * Do not translate into your own language. */ $output = __( 'html_lang_attribute' ); if ( 'html_lang_attribute' === $output || preg_match( '/[^a-zA-Z0-9-]/', $output ) ) { $output = get_locale(); $output = str_replace( '_', '-', $output ); } break; case 'text_direction': _deprecated_argument( __FUNCTION__, '2.2', sprintf( /* translators: 1: 'text_direction' argument, 2: bloginfo() function name, 3: is_rtl() function name */ __( 'The %1$s option is deprecated for the family of %2$s functions. Use the %3$s function instead.' ), '' . $show . '', 'bloginfo()', 'is_rtl()' ) ); if ( function_exists( 'is_rtl' ) ) { $output = is_rtl() ? 'rtl' : 'ltr'; } else { $output = 'ltr'; } break; case 'name': default: $output = get_option('blogname'); break; } $url = true; if (strpos($show, 'url') === false && strpos($show, 'directory') === false && strpos($show, 'home') === false) $url = false; if ( 'display' == $filter ) { if ( $url ) { /** * Filter the URL returned by get_bloginfo(). * * @since 2.0.5 * * @param mixed $output The URL returned by bloginfo(). * @param mixed $show Type of information requested. */ $output = apply_filters( 'bloginfo_url', $output, $show ); } else { /** * Filter the site information returned by get_bloginfo(). * * @since 0.71 * * @param mixed $output The requested non-URL site information. * @param mixed $show Type of information requested. */ $output = apply_filters( 'bloginfo', $output, $show ); } } return $output; } /** * Returns the Site Icon URL. * * @since 4.3.0 * * @param int $size Optional. Size of the site icon. Default 512 (pixels). * @param string $url Optional. Fallback url if no site icon is found. Default empty. * @param int $blog_id Optional. ID of the blog to get the site icon for. Default current blog. * @return string Site Icon URL. */ function get_site_icon_url( $size = 512, $url = '', $blog_id = 0 ) { if ( is_multisite() && (int) $blog_id !== get_current_blog_id() ) { switch_to_blog( $blog_id ); } $site_icon_id = get_option( 'site_icon' ); if ( $site_icon_id ) { if ( $size >= 512 ) { $size_data = 'full'; } else { $size_data = array( $size, $size ); } $url = wp_get_attachment_image_url( $site_icon_id, $size_data ); } if ( is_multisite() && ms_is_switched() ) { restore_current_blog(); } /** * Filter the site icon URL. * * @site 4.4.0 * * @param string $url Site icon URL. * @param int $size Size of the site icon. * @param int $blog_id ID of the blog to get the site icon for. */ return apply_filters( 'get_site_icon_url', $url, $size, $blog_id ); } /** * Displays the Site Icon URL. * * @since 4.3.0 * * @param int $size Optional. Size of the site icon. Default 512 (pixels). * @param string $url Optional. Fallback url if no site icon is found. Default empty. * @param int $blog_id Optional. ID of the blog to get the site icon for. Default current blog. */ function site_icon_url( $size = 512, $url = '', $blog_id = 0 ) { echo esc_url( get_site_icon_url( $size, $url, $blog_id ) ); } /** * Whether the site has a Site Icon. * * @since 4.3.0 * * @param int $blog_id Optional. ID of the blog in question. Default current blog. * @return bool Whether the site has a site icon or not. */ function has_site_icon( $blog_id = 0 ) { return (bool) get_site_icon_url( 512, '', $blog_id ); } /** * Determines whether the site has a custom logo. * * @since 4.5.0 * * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog. * @return bool Whether the site has a custom logo or not. */ function has_custom_logo( $blog_id = 0 ) { if ( is_multisite() && (int) $blog_id !== get_current_blog_id() ) { switch_to_blog( $blog_id ); } $custom_logo_id = get_theme_mod( 'custom_logo' ); if ( is_multisite() && ms_is_switched() ) { restore_current_blog(); } return (bool) $custom_logo_id; } /** * Returns a custom logo, linked to home. * * @since 4.5.0 * * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog. * @return string Custom logo markup. */ function get_custom_logo( $blog_id = 0 ) { $html = ''; if ( is_multisite() && (int) $blog_id !== get_current_blog_id() ) { switch_to_blog( $blog_id ); } $custom_logo_id = get_theme_mod( 'custom_logo' ); // We have a logo. Logo is go. if ( $custom_logo_id ) { $html = sprintf( '', esc_url( home_url( '/' ) ), wp_get_attachment_image( $custom_logo_id, 'full', false, array( 'class' => 'custom-logo', 'itemprop' => 'logo', ) ) ); } // If no logo is set but we're in the Customizer, leave a placeholder (needed for the live preview). elseif ( is_customize_preview() ) { $html = sprintf( '', esc_url( home_url( '/' ) ) ); } if ( is_multisite() && ms_is_switched() ) { restore_current_blog(); } /** * Filter the custom logo output. * * @since 4.5.0 * * @param string $html Custom logo HTML output. */ return apply_filters( 'get_custom_logo', $html ); } /** * Displays a custom logo, linked to home. * * @since 4.5.0 * * @param int $blog_id Optional. ID of the blog in question. Default is the ID of the current blog. */ function the_custom_logo( $blog_id = 0 ) { echo get_custom_logo( $blog_id ); } /** * Returns document title for the current page. * * @since 4.4.0 * * @global int $page Page number of a single post. * @global int $paged Page number of a list of posts. * * @return string Tag with the document title. */ function wp_get_document_title() { /** * Filter the document title before it is generated. * * Passing a non-empty value will short-circuit wp_get_document_title(), * returning that value instead. * * @since 4.4.0 * * @param string $title The document title. Default empty string. */ $title = apply_filters( 'pre_get_document_title', '' ); if ( ! empty( $title ) ) { return $title; } global $page, $paged; $title = array( 'title' => '', ); // If it's a 404 page, use a "Page not found" title. if ( is_404() ) { $title['title'] = __( 'Page not found' ); // If it's a search, use a dynamic search results title. } elseif ( is_search() ) { /* translators: %s: search phrase */ $title['title'] = sprintf( __( 'Search Results for “%s”' ), get_search_query() ); // If on the front page, use the site title. } elseif ( is_front_page() ) { $title['title'] = get_bloginfo( 'name', 'display' ); // If on a post type archive, use the post type archive title. } elseif ( is_post_type_archive() ) { $title['title'] = post_type_archive_title( '', false ); // If on a taxonomy archive, use the term title. } elseif ( is_tax() ) { $title['title'] = single_term_title( '', false ); /* * If we're on the blog page that is not the homepage or * a single post of any post type, use the post title. */ } elseif ( is_home() || is_singular() ) { $title['title'] = single_post_title( '', false ); // If on a category or tag archive, use the term title. } elseif ( is_category() || is_tag() ) { $title['title'] = single_term_title( '', false ); // If on an author archive, use the author's display name. } elseif ( is_author() && $author = get_queried_object() ) { $title['title'] = $author->display_name; // If it's a date archive, use the date as the title. } elseif ( is_year() ) { $title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) ); } elseif ( is_month() ) { $title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) ); } elseif ( is_day() ) { $title['title'] = get_the_date(); } // Add a page number if necessary. if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) { $title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) ); } // Append the description or site title to give context. if ( is_front_page() ) { $title['tagline'] = get_bloginfo( 'description', 'display' ); } else { $title['site'] = get_bloginfo( 'name', 'display' ); } /** * Filter the separator for the document title. * * @since 4.4.0 * * @param string $sep Document title separator. Default '-'. */ $sep = apply_filters( 'document_title_separator', '-' ); /** * Filter the parts of the document title. * * @since 4.4.0 * * @param array $title { * The document title parts. * * @type string $title Title of the viewed page. * @type string $page Optional. Page number if paginated. * @type string $tagline Optional. Site description when on home page. * @type string $site Optional. Site title when not on home page. * } */ $title = apply_filters( 'document_title_parts', $title ); $title = implode( " $sep ", array_filter( $title ) ); $title = wptexturize( $title ); $title = convert_chars( $title ); $title = esc_html( $title ); $title = capital_P_dangit( $title ); return $title; } /** * Displays title tag with content. * * @ignore * @since 4.1.0 * @since 4.4.0 Improved title output replaced `wp_title()`. * @access private */ function _wp_render_title_tag() { if ( ! current_theme_supports( 'title-tag' ) ) { return; } echo '' . wp_get_document_title() . '' . "\n"; } /** * Display or retrieve page title for all areas of blog. * * By default, the page title will display the separator before the page title, * so that the blog title will be before the page title. This is not good for * title display, since the blog title shows up on most tabs and not what is * important, which is the page that the user is looking at. * * There are also SEO benefits to having the blog title after or to the 'right' * or the page title. However, it is mostly common sense to have the blog title * to the right with most browsers supporting tabs. You can achieve this by * using the seplocation parameter and setting the value to 'right'. This change * was introduced around 2.5.0, in case backwards compatibility of themes is * important. * * @since 1.0.0 * * @global WP_Locale $wp_locale * * @param string $sep Optional, default is '»'. How to separate the various items * within the page title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @param string $seplocation Optional. Direction to display title, 'right'. * @return string|null String on retrieve, null when displaying. */ function wp_title( $sep = '»', $display = true, $seplocation = '' ) { global $wp_locale; $m = get_query_var( 'm' ); $year = get_query_var( 'year' ); $monthnum = get_query_var( 'monthnum' ); $day = get_query_var( 'day' ); $search = get_query_var( 's' ); $title = ''; $t_sep = '%WP_TITLE_SEP%'; // Temporary separator, for accurate flipping, if necessary // If there is a post if ( is_single() || ( is_home() && ! is_front_page() ) || ( is_page() && ! is_front_page() ) ) { $title = single_post_title( '', false ); } // If there's a post type archive if ( is_post_type_archive() ) { $post_type = get_query_var( 'post_type' ); if ( is_array( $post_type ) ) { $post_type = reset( $post_type ); } $post_type_object = get_post_type_object( $post_type ); if ( ! $post_type_object->has_archive ) { $title = post_type_archive_title( '', false ); } } // If there's a category or tag if ( is_category() || is_tag() ) { $title = single_term_title( '', false ); } // If there's a taxonomy if ( is_tax() ) { $term = get_queried_object(); if ( $term ) { $tax = get_taxonomy( $term->taxonomy ); $title = single_term_title( $tax->labels->name . $t_sep, false ); } } // If there's an author if ( is_author() && ! is_post_type_archive() ) { $author = get_queried_object(); if ( $author ) { $title = $author->display_name; } } // Post type archives with has_archive should override terms. if ( is_post_type_archive() && $post_type_object->has_archive ) { $title = post_type_archive_title( '', false ); } // If there's a month if ( is_archive() && ! empty( $m ) ) { $my_year = substr( $m, 0, 4 ); $my_month = $wp_locale->get_month( substr( $m, 4, 2 ) ); $my_day = intval( substr( $m, 6, 2 ) ); $title = $my_year . ( $my_month ? $t_sep . $my_month : '' ) . ( $my_day ? $t_sep . $my_day : '' ); } // If there's a year if ( is_archive() && ! empty( $year ) ) { $title = $year; if ( ! empty( $monthnum ) ) { $title .= $t_sep . $wp_locale->get_month( $monthnum ); } if ( ! empty( $day ) ) { $title .= $t_sep . zeroise( $day, 2 ); } } // If it's a search if ( is_search() ) { /* translators: 1: separator, 2: search phrase */ $title = sprintf( __( 'Search Results %1$s %2$s' ), $t_sep, strip_tags( $search ) ); } // If it's a 404 page if ( is_404() ) { $title = __( 'Page not found' ); } $prefix = ''; if ( ! empty( $title ) ) { $prefix = " $sep "; } /** * Filter the parts of the page title. * * @since 4.0.0 * * @param array $title_array Parts of the page title. */ $title_array = apply_filters( 'wp_title_parts', explode( $t_sep, $title ) ); // Determines position of the separator and direction of the breadcrumb if ( 'right' == $seplocation ) { // sep on right, so reverse the order $title_array = array_reverse( $title_array ); $title = implode( " $sep ", $title_array ) . $prefix; } else { $title = $prefix . implode( " $sep ", $title_array ); } /** * Filter the text of the page title. * * @since 2.0.0 * * @param string $title Page title. * @param string $sep Title separator. * @param string $seplocation Location of the separator (left or right). */ $title = apply_filters( 'wp_title', $title, $sep, $seplocation ); // Send it out if ( $display ) { echo $title; } else { return $title; } } /** * Display or retrieve page title for post. * * This is optimized for single.php template file for displaying the post title. * * It does not support placing the separator after the title, but by leaving the * prefix parameter empty, you can set the title separator manually. The prefix * does not automatically place a space between the prefix, so if there should * be a space, the parameter value will need to have it at the end. * * @since 0.71 * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving. */ function single_post_title( $prefix = '', $display = true ) { $_post = get_queried_object(); if ( !isset($_post->post_title) ) return; /** * Filter the page title for a single post. * * @since 0.71 * * @param string $_post_title The single post page title. * @param object $_post The current queried object as returned by get_queried_object(). */ $title = apply_filters( 'single_post_title', $_post->post_title, $_post ); if ( $display ) echo $prefix . $title; else return $prefix . $title; } /** * Display or retrieve title for a post type archive. * * This is optimized for archive.php and archive-{$post_type}.php template files * for displaying the title of the post type. * * @since 3.1.0 * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving, null when displaying or failure. */ function post_type_archive_title( $prefix = '', $display = true ) { if ( ! is_post_type_archive() ) return; $post_type = get_query_var( 'post_type' ); if ( is_array( $post_type ) ) $post_type = reset( $post_type ); $post_type_obj = get_post_type_object( $post_type ); /** * Filter the post type archive title. * * @since 3.1.0 * * @param string $post_type_name Post type 'name' label. * @param string $post_type Post type. */ $title = apply_filters( 'post_type_archive_title', $post_type_obj->labels->name, $post_type ); if ( $display ) echo $prefix . $title; else return $prefix . $title; } /** * Display or retrieve page title for category archive. * * Useful for category template files for displaying the category page title. * The prefix does not automatically place a space between the prefix, so if * there should be a space, the parameter value will need to have it at the end. * * @since 0.71 * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving. */ function single_cat_title( $prefix = '', $display = true ) { return single_term_title( $prefix, $display ); } /** * Display or retrieve page title for tag post archive. * * Useful for tag template files for displaying the tag page title. The prefix * does not automatically place a space between the prefix, so if there should * be a space, the parameter value will need to have it at the end. * * @since 2.3.0 * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving. */ function single_tag_title( $prefix = '', $display = true ) { return single_term_title( $prefix, $display ); } /** * Display or retrieve page title for taxonomy term archive. * * Useful for taxonomy term template files for displaying the taxonomy term page title. * The prefix does not automatically place a space between the prefix, so if there should * be a space, the parameter value will need to have it at the end. * * @since 3.1.0 * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving. */ function single_term_title( $prefix = '', $display = true ) { $term = get_queried_object(); if ( !$term ) return; if ( is_category() ) { /** * Filter the category archive page title. * * @since 2.0.10 * * @param string $term_name Category name for archive being displayed. */ $term_name = apply_filters( 'single_cat_title', $term->name ); } elseif ( is_tag() ) { /** * Filter the tag archive page title. * * @since 2.3.0 * * @param string $term_name Tag name for archive being displayed. */ $term_name = apply_filters( 'single_tag_title', $term->name ); } elseif ( is_tax() ) { /** * Filter the custom taxonomy archive page title. * * @since 3.1.0 * * @param string $term_name Term name for archive being displayed. */ $term_name = apply_filters( 'single_term_title', $term->name ); } else { return; } if ( empty( $term_name ) ) return; if ( $display ) echo $prefix . $term_name; else return $prefix . $term_name; } /** * Display or retrieve page title for post archive based on date. * * Useful for when the template only needs to display the month and year, * if either are available. The prefix does not automatically place a space * between the prefix, so if there should be a space, the parameter value * will need to have it at the end. * * @since 0.71 * * @global WP_Locale $wp_locale * * @param string $prefix Optional. What to display before the title. * @param bool $display Optional, default is true. Whether to display or retrieve title. * @return string|void Title when retrieving. */ function single_month_title($prefix = '', $display = true ) { global $wp_locale; $m = get_query_var('m'); $year = get_query_var('year'); $monthnum = get_query_var('monthnum'); if ( !empty($monthnum) && !empty($year) ) { $my_year = $year; $my_month = $wp_locale->get_month($monthnum); } elseif ( !empty($m) ) { $my_year = substr($m, 0, 4); $my_month = $wp_locale->get_month(substr($m, 4, 2)); } if ( empty($my_month) ) return false; $result = $prefix . $my_month . $prefix . $my_year; if ( !$display ) return $result; echo $result; } /** * Display the archive title based on the queried object. * * @since 4.1.0 * * @see get_the_archive_title() * * @param string $before Optional. Content to prepend to the title. Default empty. * @param string $after Optional. Content to append to the title. Default empty. */ function the_archive_title( $before = '', $after = '' ) { $title = get_the_archive_title(); if ( ! empty( $title ) ) { echo $before . $title . $after; } } /** * Retrieve the archive title based on the queried object. * * @since 4.1.0 * * @return string Archive title. */ function get_the_archive_title() { if ( is_category() ) { $title = sprintf( __( 'Category: %s' ), single_cat_title( '', false ) ); } elseif ( is_tag() ) { $title = sprintf( __( 'Tag: %s' ), single_tag_title( '', false ) ); } elseif ( is_author() ) { $title = sprintf( __( 'Author: %s' ), '' . get_the_author() . '' ); } elseif ( is_year() ) { $title = sprintf( __( 'Year: %s' ), get_the_date( _x( 'Y', 'yearly archives date format' ) ) ); } elseif ( is_month() ) { $title = sprintf( __( 'Month: %s' ), get_the_date( _x( 'F Y', 'monthly archives date format' ) ) ); } elseif ( is_day() ) { $title = sprintf( __( 'Day: %s' ), get_the_date( _x( 'F j, Y', 'daily archives date format' ) ) ); } elseif ( is_tax( 'post_format' ) ) { if ( is_tax( 'post_format', 'post-format-aside' ) ) { $title = _x( 'Asides', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-gallery' ) ) { $title = _x( 'Galleries', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-image' ) ) { $title = _x( 'Images', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-video' ) ) { $title = _x( 'Videos', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-quote' ) ) { $title = _x( 'Quotes', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-link' ) ) { $title = _x( 'Links', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-status' ) ) { $title = _x( 'Statuses', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-audio' ) ) { $title = _x( 'Audio', 'post format archive title' ); } elseif ( is_tax( 'post_format', 'post-format-chat' ) ) { $title = _x( 'Chats', 'post format archive title' ); } } elseif ( is_post_type_archive() ) { $title = sprintf( __( 'Archives: %s' ), post_type_archive_title( '', false ) ); } elseif ( is_tax() ) { $tax = get_taxonomy( get_queried_object()->taxonomy ); /* translators: 1: Taxonomy singular name, 2: Current taxonomy term */ $title = sprintf( __( '%1$s: %2$s' ), $tax->labels->singular_name, single_term_title( '', false ) ); } else { $title = __( 'Archives' ); } /** * Filter the archive title. * * @since 4.1.0 * * @param string $title Archive title to be displayed. */ return apply_filters( 'get_the_archive_title', $title ); } /** * Display category, tag, or term description. * * @since 4.1.0 * * @see get_the_archive_description() * * @param string $before Optional. Content to prepend to the description. Default empty. * @param string $after Optional. Content to append to the description. Default empty. */ function the_archive_description( $before = '', $after = '' ) { $description = get_the_archive_description(); if ( $description ) { echo $before . $description . $after; } } /** * Retrieve category, tag, or term description. * * @since 4.1.0 * * @return string Archive description. */ function get_the_archive_description() { /** * Filter the archive description. * * @since 4.1.0 * * @see term_description() * * @param string $description Archive description to be displayed. */ return apply_filters( 'get_the_archive_description', term_description() ); } /** * Retrieve archive link content based on predefined or custom code. * * The format can be one of four styles. The 'link' for head element, 'option' * for use in the select element, 'html' for use in list (either ol or ul HTML * elements). Custom content is also supported using the before and after * parameters. * * The 'link' format uses the `` HTML element with the **archives** * relationship. The before and after parameters are not used. The text * parameter is used to describe the link. * * The 'option' format uses the option HTML element for use in select element. * The value is the url parameter and the before and after parameters are used * between the text description. * * The 'html' format, which is the default, uses the li HTML element for use in * the list HTML elements. The before parameter is before the link and the after * parameter is after the closing link. * * The custom format uses the before parameter before the link ('a' HTML * element) and the after parameter after the closing link tag. If the above * three values for the format are not used, then custom format is assumed. * * @since 1.0.0 * * @param string $url URL to archive. * @param string $text Archive text description. * @param string $format Optional, default is 'html'. Can be 'link', 'option', 'html', or custom. * @param string $before Optional. Content to prepend to the description. Default empty. * @param string $after Optional. Content to append to the description. Default empty. * @return string HTML link content for archive. */ function get_archives_link($url, $text, $format = 'html', $before = '', $after = '') { $text = wptexturize($text); $url = esc_url($url); if ('link' == $format) $link_html = "\t\n"; elseif ('option' == $format) $link_html = "\t\n"; elseif ('html' == $format) $link_html = "\t
  • $before$text$after
  • \n"; else // custom $link_html = "\t$before$text$after\n"; /** * Filter the archive link content. * * @since 2.6.0 * @since 4.5.0 Added the `$url`, `$text`, `$format`, `$before`, and `$after` parameters. * * @param string $link_html The archive HTML link content. * @param string $url URL to archive. * @param string $text Archive text description. * @param string $format Link format. Can be 'link', 'option', 'html', or custom. * @param string $before Content to prepend to the description. * @param string $after Content to append to the description. */ return apply_filters( 'get_archives_link', $link_html, $url, $text, $format, $before, $after ); } /** * Display archive links based on type and format. * * @since 1.2.0 * @since 4.4.0 $post_type arg was added. * * @see get_archives_link() * * @global wpdb $wpdb * @global WP_Locale $wp_locale * * @param string|array $args { * Default archive links arguments. Optional. * * @type string $type Type of archive to retrieve. Accepts 'daily', 'weekly', 'monthly', * 'yearly', 'postbypost', or 'alpha'. Both 'postbypost' and 'alpha' * display the same archive link list as well as post titles instead * of displaying dates. The difference between the two is that 'alpha' * will order by post title and 'postbypost' will order by post date. * Default 'monthly'. * @type string|int $limit Number of links to limit the query to. Default empty (no limit). * @type string $format Format each link should take using the $before and $after args. * Accepts 'link' (`` tag), 'option' (`