WordPress.org

Make WordPress Core

Ticket #11914: 11914.7.diff

File 11914.7.diff, 15.9 KB (added by miqrogroove, 10 years ago)

Refreshed

  • wp-admin/includes/schema.php

     
    146146  PRIMARY KEY  (ID),
    147147  KEY post_name (post_name),
    148148  KEY type_status_date (post_type,post_status,post_date,ID),
    149   KEY post_parent (post_parent)
     149  KEY post_parent (post_parent),
     150  KEY post_author (post_author)
    150151) $charset_collate;
    151152CREATE TABLE $wpdb->users (
    152153  ID bigint(20) unsigned NOT NULL auto_increment,
  • wp-admin/includes/template.php

     
    18241824}
    18251825
    18261826/**
    1827  * {@internal Missing Short Description}}
     1827 * Generate HTML for a single row on the users.php admin panel.
    18281828 *
    1829  * @since unknown
     1829 * @since 2.1.0
    18301830 *
    1831  * @param unknown_type $user_object
    1832  * @param unknown_type $style
    1833  * @param unknown_type $role
    1834  * @return unknown
     1831 * @param object $user_object
     1832 * @param string $style Optional. Attributes added to the TR element.  Must be sanitized.
     1833 * @param string $role Key for the $wp_roles array.
     1834 * @param int $numposts Optional. Post count to display for this user.  Defaults to zero, as in, a new user has made zero posts.
     1835 * @return string
    18351836 */
    1836 function user_row( $user_object, $style = '', $role = '' ) {
     1837function user_row( $user_object, $style = '', $role = '', $numposts = 0 ) {
    18371838        global $wp_roles;
    18381839
    18391840        $current_user = wp_get_current_user();
     
    18491850                $short_url = substr( $short_url, 0, -1 );
    18501851        if ( strlen( $short_url ) > 35 )
    18511852                $short_url = substr( $short_url, 0, 32 ).'...';
    1852         $numposts = get_usernumposts( $user_object->ID );
    18531853        $checkbox = '';
    18541854        // Check if the user for this row is editable
    18551855        if ( current_user_can( 'edit_user', $user_object->ID ) ) {
  • wp-admin/users.php

     
    208208        $userspage = isset($_GET['userspage']) ? $_GET['userspage'] : null;
    209209        $role = isset($_GET['role']) ? $_GET['role'] : null;
    210210
    211         // Query the users
     211        // Query the user IDs for this page
    212212        $wp_user_search = new WP_User_Search($usersearch, $userspage, $role);
    213213
     214        // Query the post counts for this page
     215        $post_counts = count_many_users_posts($wp_user_search->get_results());
     216
     217        // Query the users for this page
     218        cache_users($wp_user_search->get_results());
     219
    214220        $messages = array();
    215221        if ( isset($_GET['update']) ) :
    216222                switch($_GET['update']) {
     
    263269<form id="list-filter" action="" method="get">
    264270<ul class="subsubsub">
    265271<?php
    266 $role_links = array();
    267 $avail_roles = array();
    268 $users_of_blog = get_users_of_blog();
    269 $total_users = count( $users_of_blog );
    270 foreach ( (array) $users_of_blog as $b_user ) {
    271         $b_roles = unserialize($b_user->meta_value);
    272         foreach ( (array) $b_roles as $b_role => $val ) {
    273                 if ( !isset($avail_roles[$b_role]) )
    274                         $avail_roles[$b_role] = 0;
    275                 $avail_roles[$b_role]++;
    276         }
    277 }
     272$users_of_blog = count_users();
     273$total_users = $users_of_blog['total_users'];
     274$avail_roles =& $users_of_blog['avail_roles'];
    278275unset($users_of_blog);
    279276
    280277$current_role = false;
    281278$class = empty($role) ? ' class="current"' : '';
     279$role_links = array();
    282280$role_links[] = "<li><a href='users.php'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
    283281foreach ( $wp_roles->get_names() as $this_role => $name ) {
    284282        if ( !isset($avail_roles[$this_role]) )
     
    372370        $role = array_shift($roles);
    373371
    374372        $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
    375         echo "\n\t" . user_row($user_object, $style, $role);
     373        echo "\n\t", user_row($user_object, $style, $role, $post_counts[(string)$userid]);
    376374}
    377375?>
    378376</tbody>
  • wp-includes/author-template.php

     
    151151 *
    152152 * @since 1.5
    153153 * @uses $post The current post in the Loop's DB object.
    154  * @uses get_usernumposts()
     154 * @uses count_user_posts()
    155155 * @return int The number of posts by the author.
    156156 */
    157157function get_the_author_posts() {
    158158        global $post;
    159         return get_usernumposts($post->post_author);
     159        return count_user_posts($post->post_author);
    160160}
    161161
    162162/**
  • wp-includes/pluggable.php

     
    139139}
    140140endif;
    141141
     142if ( !function_exists('cache_users') ) :
     143/**
     144 * Retrieve info for user lists to prevent multiple queries by get_userdata()
     145 *
     146 * @since 3.0.0
     147 *
     148 * @param array $users User ID numbers list
     149 */
     150function cache_users( $users ) {
     151        global $wpdb;
     152
     153        $clean = array();
     154        foreach($users as $id) {
     155                $id = (int) $id;
     156                if (wp_cache_get($id, 'users')) {
     157                        // seems to be cached already
     158                } else {
     159                        $clean[] = $id;
     160                }
     161        }
     162
     163        if ( 0 == count($clean) )
     164                return;
     165
     166        $list = implode(',', $clean);
     167
     168        $results = $wpdb->get_results("SELECT * FROM $wpdb->users WHERE ID IN ($list)");
     169   
     170        _fill_many_users($results);
     171}
     172endif;
     173
    142174if ( !function_exists('get_user_by') ) :
    143175/**
    144176 * Retrieve user info by a given field
  • wp-includes/post.php

     
    36523652 * @return string SQL code that can be added to a where clause.
    36533653 */
    36543654function get_private_posts_cap_sql($post_type) {
    3655         global $user_ID;
    3656         $cap = '';
     3655        return get_posts_by_author_sql($post_type, FALSE);
     3656}
    36573657
     3658/**
     3659 * Retrieve the post SQL based on capability, author, and type.
     3660 *
     3661 * See above for full description.
     3662 *
     3663 * @since 3.0.0
     3664 * @param string $post_type currently only supports 'post' or 'page'.
     3665 * @param bool $full Optional.  Returns a full WHERE statement instead of just an 'andalso' term.
     3666 * @param int $post_author Optional.  Query posts having a single author ID.
     3667 * @return string SQL WHERE code that can be added to a query.
     3668 */
     3669function get_posts_by_author_sql($post_type, $full = TRUE, $post_author = NULL) {
     3670        global $user_ID, $wpdb;
     3671
    36583672        // Private posts
    36593673        if ($post_type == 'post') {
    36603674                $cap = 'read_private_posts';
     
    36633677                $cap = 'read_private_pages';
    36643678        // Dunno what it is, maybe plugins have their own post type?
    36653679        } else {
     3680                $cap = '';
    36663681                $cap = apply_filters('pub_priv_sql_capability', $cap);
    36673682
    36683683                if (empty($cap)) {
    36693684                        // We don't know what it is, filters don't change anything,
    36703685                        // so set the SQL up to return nothing.
    3671                         return '1 = 0';
     3686                        return ' 1 = 0 ';
    36723687                }
    36733688        }
    36743689
    3675         $sql = '(post_status = \'publish\'';
     3690        if ($full) {
     3691                if (is_null($post_author)) {
     3692                        $sql = $wpdb->prepare('WHERE post_type = %s AND ', $post_type);
     3693                } else {
     3694                        $sql = $wpdb->prepare('WHERE post_author = %d AND post_type = %s AND ', $post_author, $post_type);
     3695                }
     3696        } else {
     3697                $sql = '';
     3698        }
    36763699
     3700        $sql .= "(post_status = 'publish'";
     3701
    36773702        if (current_user_can($cap)) {
    36783703                // Does the user have the capability to view private posts? Guess so.
    3679                 $sql .= ' OR post_status = \'private\'';
     3704                $sql .= " OR post_status = 'private'";
    36803705        } elseif (is_user_logged_in()) {
    36813706                // Users can view their own private posts.
    3682                 $sql .= ' OR post_status = \'private\' AND post_author = \'' . $user_ID . '\'';
    3683         }
     3707                $id = (int) $user_ID;
     3708                if (is_null($post_author) || !$full) {
     3709                        $sql .= " OR post_status = 'private' AND post_author = $id";
     3710                } elseif ($id == (int)$post_author) {
     3711                        $sql .= " OR post_status = 'private'";
     3712                } // else none
     3713        } // else none
    36843714
    36853715        $sql .= ')';
    36863716
  • wp-includes/user.php

     
    148148 * @param int $userid User ID.
    149149 * @return int Amount of posts user has written.
    150150 */
    151 function get_usernumposts($userid) {
     151function count_user_posts($userid) {
    152152        global $wpdb;
    153         $userid = (int) $userid;
    154         $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_author = %d AND post_type = 'post' AND ", $userid) . get_private_posts_cap_sql('post'));
     153
     154        $where = get_posts_by_author_sql('post', TRUE, $userid);
     155
     156        $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
     157
    155158        return apply_filters('get_usernumposts', $count, $userid);
    156159}
    157160
    158161/**
     162 * Number of posts written by a list of users.
     163 *
     164 * @since 3.0.0
     165 * @param array $userid User ID number list.
     166 * @return array Amount of posts each user has written.
     167 */
     168function count_many_users_posts($users) {
     169        global $wpdb;
     170       
     171        if (0 == count($users))
     172                return array();
     173           
     174        $userlist = implode(',', $users);
     175        $where = get_posts_by_author_sql('post');
     176
     177        $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
     178
     179        $count = array();
     180        foreach($result as $row) {
     181                $count[$row[0]] = $row[1];
     182        }
     183
     184        foreach($users as $id) {
     185                $id = (string) $id;
     186                if (!isset($count[$id]))
     187                        $count[$id] = 0;
     188        }
     189
     190        return $count;
     191}
     192
     193/**
    159194 * Check that the user login name and password is correct.
    160195 *
    161196 * @since 0.71
     
    342377        return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
    343378}
    344379
     380/**
     381 * Count number of users who have each of the user roles.
     382 *
     383 * Assumes there are neither duplicated nor orphaned capabilities meta_values.
     384 * Assumes role names are unique phrases.  Same assumption made by WP_User_Search::prepare_query()
     385 * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
     386 * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
     387 *
     388 * @since 3.0.0
     389 * @param string $strategy 'time' or 'memory'
     390 * @return array Includes a grand total and an array of counts indexed by role strings.
     391 */
     392function count_users($strategy = 'time') {
     393        global $wpdb, $blog_id, $wp_roles;
     394
     395        // Initialize
     396        $id = (int) $blog_id;
     397        $blog_prefix = $wpdb->get_blog_prefix($id);
     398        $result = array();
     399
     400        if ('time' == $strategy) {
     401                $avail_roles = $wp_roles->get_names();
     402
     403                // Build a CPU-intensive query that will return concise information.
     404                $select_count = array();
     405                foreach ( $avail_roles as $this_role => $name ) {
     406                        $select_count[] = "COUNT(NULLIF(`meta_value` LIKE '%" . like_escape($this_role) . "%', FALSE))";
     407                }
     408                $select_count = implode(', ', $select_count);
     409
     410                // Add the meta_value index to the selection list, then run the query.
     411                $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
     412
     413                // Run the previous loop again to associate results with role names.
     414                $col = 0;
     415                $role_counts = array();
     416                foreach ( $avail_roles as $this_role => $name ) {
     417                        $count = (int) $row[$col++];
     418                        if ($count > 0) {
     419                                $role_counts[$this_role] = $count;
     420                        }
     421                }
     422
     423                // Get the meta_value index from the end of the result set.
     424                $total_users = (int) $row[$col];
     425
     426                $result['total_users'] = $total_users;
     427                $result['avail_roles'] =& $role_counts;
     428        } else {
     429                $avail_roles = array();
     430
     431                $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
     432
     433                foreach ( $users_of_blog as $caps_meta ) {
     434                        $b_roles = unserialize($caps_meta);
     435                        if ( is_array($b_roles) ) {
     436                                foreach ( $b_roles as $b_role => $val ) {
     437                                        if ( isset($avail_roles[$b_role]) ) {
     438                                                $avail_roles[$b_role]++;
     439                                        } else {
     440                                                $avail_roles[$b_role] = 1;
     441                                        }
     442                                }
     443                        }
     444                }
     445
     446                $result['total_users'] = count( $users_of_blog );
     447                $result['avail_roles'] =& $avail_roles;
     448        }
     449
     450        return $result;
     451}
     452
    345453//
    346454// Private helper functions
    347455//
     
    498606 *
    499607 * The finished user data is cached, but the cache is not used to fill in the
    500608 * user data for the given object. Once the function has been used, the cache
    501  * should be used to retrieve user data. The purpose seems then to be to ensure
    502  * that the data in the object is always fresh.
     609 * should be used to retrieve user data. The intention is if the current data
     610 * had been cached already, there would be no need to call this function.
    503611 *
    504612 * @access private
    505613 * @since 2.5.0
     
    508616 * @param object $user The user data object.
    509617 */
    510618function _fill_user( &$user ) {
     619        $metavalues = get_user_metavalues(array($user->ID));
     620        _fill_single_user($user, $metavalues[$user->ID]);
     621}
     622
     623/**
     624 * Perform the query to get the $metavalues array(s) needed by _fill_user and _fill_many_users
     625 *
     626 * @since 3.0.0
     627 * @param array $ids User ID numbers list.
     628 * @return array of arrays. The array is indexed by user_id, containing $metavalues object arrays.
     629 */
     630function get_user_metavalues($ids) {
    511631        global $wpdb;
    512632
     633        $clean = array_map('intval', $ids);
     634        if ( 0 == count($clean) )
     635                return $objects;
     636
     637        $list = implode(',', $clean);
     638
    513639        $show = $wpdb->hide_errors();
    514         $metavalues = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->usermeta WHERE user_id = %d", $user->ID));
     640        $metavalues = $wpdb->get_results("SELECT user_id, meta_key, meta_value FROM $wpdb->usermeta WHERE user_id IN ($list)");
    515641        $wpdb->show_errors($show);
    516642
    517         if ( $metavalues ) {
    518                 foreach ( (array) $metavalues as $meta ) {
    519                         $value = maybe_unserialize($meta->meta_value);
    520                         $user->{$meta->meta_key} = $value;
    521                 }
     643        $objects = array();
     644        foreach($clean as $id) {
     645                $objects[$id] = array();
    522646        }
     647        foreach($metavalues as $meta_object) {
     648                $objects[$meta_object->user_id][] = $meta_object;
     649        }
    523650
     651        return $objects;
     652}
     653
     654/**
     655 * Unserialize user metadata, fill $user object, then cache everything.
     656 *
     657 * @since 3.0.0
     658 * @param object $user The User object.
     659 * @param array $metavalues An array of objects provided by get_user_metavalues()
     660 */
     661function _fill_single_user( &$user, &$metavalues ) {
     662        global $wpdb;
     663
     664        foreach ( $metavalues as $meta ) {
     665                $value = maybe_unserialize($meta->meta_value);
     666                $user->{$meta->meta_key} = $value;
     667        }
     668
    524669        $level = $wpdb->prefix . 'user_level';
    525670        if ( isset( $user->{$level} ) )
    526671                $user->user_level = $user->{$level};
     
    533678        if ( isset($user->description) )
    534679                $user->user_description = $user->description;
    535680
    536         wp_cache_add($user->ID, $user, 'users');
    537         wp_cache_add($user->user_login, $user->ID, 'userlogins');
    538         wp_cache_add($user->user_email, $user->ID, 'useremail');
    539         wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
     681        update_user_caches($user);
    540682}
    541683
    542684/**
     685 * Take an array of user objects, fill them with metas, and cache them.
     686 *
     687 * @since 3.0.0
     688 * @param array $users User objects
     689 * @param array $metas User metavalues objects
     690 */
     691function _fill_many_users( &$users ) {
     692        $ids = array();
     693        foreach($users as $user_object) {
     694                $ids[] = $user_object->ID;
     695        }
     696
     697    $metas = get_user_metavalues($ids);
     698
     699        foreach($users as $user_object) {
     700                if (isset($metas[$user_object->ID])) {
     701                _fill_single_user($user_object, $metas[$user_object->ID]);
     702                }
     703        }
     704}
     705
     706/**
    543707 * Sanitize every user field.
    544708 *
    545709 * If the context is 'raw', then the user object or array will get minimal santization of the int fields.
     
    656820}
    657821
    658822/**
     823 * Update all user caches
     824 *
     825 * @since 3.0.0
     826 *
     827 * @param object $user User object to be cached
     828 */
     829function update_user_caches(&$user) {
     830        wp_cache_add($user->ID, $user, 'users');
     831        wp_cache_add($user->user_login, $user->ID, 'userlogins');
     832        wp_cache_add($user->user_email, $user->ID, 'useremail');
     833        wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
     834}
     835
     836/**
    659837 * Clean all user caches
    660838 *
    661  * @since 3.0
     839 * @since 3.0.0
    662840 *
    663841 * @param int $id User ID
    664  * @return void
    665842 */
    666843function clean_user_cache($id) {
    667844        $user = new WP_User($id);