Делаем список авторов для WordPress

В WordPress есть поддержка большого количества авторов и пользователей, однако слабо реализован механизм получения и вывода списка. Единственная функция wp_list_authors возвращает html код, содержащий unordered list (UL>LI) авторов, отсортированный по имени пользователя. Этого достаточно для большинства блогов, в которых пишет один или несколько авторов. Для вывода большого количества авторов стандартный механизм очень ресурсоёмкий и нет возможности получения списка в другом формате, хотя бы в массиве, для дальнейшей обработки. Очевидно, разработчики положили эту часть работы на плечи сторонних программистов, авторов плагинов и всяческих хаков WordPress. Порывшись по репозитарию плагинов и по блогам разработчиков, я выяснил, что все предлагаемые решения имеют те же недостатки — повышенная ресурсоёмоксть и отсутствие хоть какой-то универсальности. Так и пришла идея разработать свой плагин.

Идея плагина для WordPress Sorted Author List

  1. Список должен сортироваться, т.е. пользователь должен иметь возможность отсортировать список авторов по количеству статей (постов), по количеству комментариев и по дате входа.
  2. Список должен быть постраничный. Не выводить же все 10000 пользователей на одной странице?
  3. Согласно п. 1, нужно вывести количество статей автора и количество комментариев.
  4. Должна быть возможность вывести аватар автора и может быть другие данные (сайт, ICQ и т.п.)
  5. Возможность ввести внутренний рейтинг на сайте. Можно прикрутить голосование за статьи и авторам начислять «+» и «-«. Оставим этот пункт на будущее, но будем иметь ввиду, что нам понадобится обновление нашего плагина, проверка версии и все другие возможности.

Приступаем к разработке плагина

Перед тем как писать какой-то код, я решил заглянуть в код вордпресса и посмотреть, что же он там делает функция (принято называть такие функции — 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 и уже создать рабочую версию плагина. Вопросы или уточнения и дополнения Вы можете оставить в комментариях.

Следите за обновлениями.

Об авторе AlexeyBalin

AlexeyBalin
Разрабатываю и поддерживаю большое количество сайтов, работающих на выделенных серверах и виртуальных хостинг-аккаунтах.


Запись опубликована в рубрике Программирование с метками , , , . Добавьте в закладки постоянную ссылку.


Поделиться с друзьями




5 комментариев: Делаем список авторов для WordPress

    Добавить комментарий