В WordPress есть поддержка большого количества авторов и пользователей, однако слабо реализован механизм получения и вывода списка. Единственная функция wp_list_authors возвращает html код, содержащий unordered list (UL>LI) авторов, отсортированный по имени пользователя. Этого достаточно для большинства блогов, в которых пишет один или несколько авторов. Для вывода большого количества авторов стандартный механизм очень ресурсоёмкий и нет возможности получения списка в другом формате, хотя бы в массиве, для дальнейшей обработки. Очевидно, разработчики положили эту часть работы на плечи сторонних программистов, авторов плагинов и всяческих хаков WordPress. Порывшись по репозитарию плагинов и по блогам разработчиков, я выяснил, что все предлагаемые решения имеют те же недостатки — повышенная ресурсоёмоксть и отсутствие хоть какой-то универсальности. Так и пришла идея разработать свой плагин.
Идея плагина для WordPress Sorted Author List
- Список должен сортироваться, т.е. пользователь должен иметь возможность отсортировать список авторов по количеству статей (постов), по количеству комментариев и по дате входа.
- Список должен быть постраничный. Не выводить же все 10000 пользователей на одной странице?
- Согласно п. 1, нужно вывести количество статей автора и количество комментариев.
- Должна быть возможность вывести аватар автора и может быть другие данные (сайт, ICQ и т.п.)
- Возможность ввести внутренний рейтинг на сайте. Можно прикрутить голосование за статьи и авторам начислять «+» и «-«. Оставим этот пункт на будущее, но будем иметь ввиду, что нам понадобится обновление нашего плагина, проверка версии и все другие возможности.
Приступаем к разработке плагина
Перед тем как писать какой-то код, я решил заглянуть в код вордпресса и посмотреть, что же он там делает функция (принято называть такие функции — Template Tag) wp_list_authors. Наиболее важные куски кода:
Получаем список всех пользователей:
1 | $users = get_users_of_blog(); |
Нам это не подходит, мы рассчитываем на большой объем авторов.
Получаем количество постов по каждому автору, с группировкой по авторам
1 2 3 4 5 6 7 | $author_count = array(); foreach ( (array) $wpdb->get_results(" SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author") as $row ) $author_count[$row->post_author] = $row->count; |
Нет смысла тестировать сколько времени будет выполнятся такой запрос при 10000 записей от 1000 авторов ;-), достаточно сделать EXPLAIN этого запроса:
1 2 3 4 | EXPLAIN SELECT DISTINCT post_author, COUNT(ID) AS COUNT FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish' GROUP BY post_author |
На лицо все «радости», на которые способен MySQL:
Using where; Using temporary; Using filesort — т.е. MySQL создаст временную таблицу и, дополнительно, будет использовать файловую систему для сортировки данных, что увеличивает время выполнения запроса и нагрузку на сервер.
Таким образом, есть смысл добавить свою табличку в базу и кэшировать в нее счетчики. Табличку я назвал wp_authors (точнее $wpdb->prefix.’authors’, где $wpdb->prefix это тот же $table_prefix, который задается в wp-config.php. Далее в статье я буду использовать названия таблиц с префиксом wp_, однако в примерах кода префикс будет в виде переменной)
1 2 3 4 5 6 7 8 9 10 11 12 | $create_sql = "CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."authors` ( `user_id` smallint(5) UNSIGNED NOT NULL, `user_role` varchar(32) NOT NULL, `post_count` int(11) UNSIGNED NOT NULL, `comment_count` int(11) UNSIGNED NOT NULL, `dt_login` datetime NOT NULL, PRIMARY KEY (`user_id`), KEY `user_role` (`user_role`), KEY `post_count` (`post_count`), KEY `comment_count` (`comment_count`), KEY `dt_login` (`dt_login`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"; |
user_id — это поле ID из wp_users (не понятно почему, но так приянто в wordpress, что в главной таблице первичный ключ ID, а в связанных таблицах его название меняется на имя_таблицы_в_единственном_числе_id )
user_role — Роль или по-другому уровень пользователя — это штуковина совсем запрятана в таблице wp_usermeta в поле meta_value где meta_key = ‘wp_capabilities’. Нам она может понадобится, если мы захотим отфильтровать только авторов или только редакторов.
post_count — счетчик опубликованных статей
comment_count — счетчик опубликованных комментариев
dt_login — дата входа
Рейтинг специально не вводим, что бы был повод выпустить обновление плагина.
По каждому полю делаем индекс, что бы сортировка происходила быстрее.
Теперь предстоит внести существующие данные в новую таблицу. Для это таки придется выполнить запрос, который приведен выше. Но, так как он захватит только тех авторов, которые имеют опубликованные статьи, нам нужно зацепить остальных и выбрать для них роли из wp_usermeta. Потом объединить данные и внести изменения в таблицу. В результате получается вот такой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //Все пользователи $users = get_users_of_blog(); //получаем роли (права) $users_meta = $wpdb->get_results(" SELECT user_id, meta_key, meta_value FROM $wpdb->usermeta WHERE meta_key LIKE '%_capabilities'" ); //создаем массивчик по user_id $author_meta=array(); foreach ( (array) $users_meta as $row ) { $meta = array_keys(unserialize($row->meta_value)); $author_meta[$row->user_id] = $meta[0]; } //Теперь готовим данные $values =array(); foreach ( (array) $users as $user ) $values[] = "($user->ID,'".$author_meta[$user->ID]."',0,0,0)"; if( count( $values ) ) $wpdb->query("REPLACE into `".$wpdb->prefix."authors` VALUES".join(",", $values)); //Обновляем счетчик опубликованных статей $wpdb->query(" UPDATE `".$wpdb->prefix."authors` a SET a.post_count = ( SELECT COUNT(*) FROM `$wpdb->posts` WHERE post_author = a.user_id AND post_type = 'post' AND post_status = 'publish' ) "); //Обновляем счетчик опубликованных комментариев $wpdb->query(" UPDATE `".$wpdb->prefix."authors` a SET a.comment_count = ( SELECT COUNT(*) FROM `$wpdb->comments` c WHERE c.user_id = a.user_id AND comment_approved = 1 )" ); |
Вот этот код уже можно использовать для создания инсталлятора нашего плагина. В следующей статье я собираюсь рассказать о том как выбрать имя плагина, зарегистрировать его в репозитории плагинов wordpress.org и уже создать рабочую версию плагина. Вопросы или уточнения и дополнения Вы можете оставить в комментариях.
5 комментариев: Делаем список авторов для WordPress