Рассмотрим пример реализации страниц пользователей через плагин, который будет срабатывать на событие OnPageNotFound. В настройках можно включить редирект цифровых URL (/users/1 -> /users/admin), а так же строгий режим URL (редирект /users/admin/ -> /users/admin).

Хочу заметить, что у меня на сайте отключен суффикс контейнера, а так же у типа содержимого «HTML» убрано расширение. Однако плагин должен работать при любом раскладе, даже на настройках по умолчанию (суффикс "/", расширение ".html").

Для начала, создадим страницу, которая у нас будет выводить информацию о пользователе, либо список всех пользователей, если отсутствует идентификатор. Устанавливаем псевдоним, у меня «users», в поле содержимое:

[[!+internalKey:is=``:then=`[[!$page_users_list]]`:else=`[[!$page_user_info]]`]]

Чанк page_users_list выведет список пользователей:

[[!pdoPage? 
    &element=`pdoUsers`
    &tpl=`users_list_tpl`
    &sortdir=`asc`
    &leftJoin=`{"Author":{"class":"TicketAuthor","on":"Author.id=modUser.id"}}`
    &select=`{"modUser":"*", "Author":"createdon,visitedon,tickets,comments,rating,views"}`
]]
[[!+page.nav]]

Чанк users_list_tpl:

<div class="container-fluid user-row">
    <div class="col-md-2">
        <img src="[[+photo:phpthumbon=`w=70`]]" alt="[[+username]]" />
    </div>
    <div class="col-md-4">
        <a href="users/[[+username]]">[[+fullname:default=`[[+username]]`]]</a>
        <br>Зарегистрирован: [[+createdon:dateAgo]]
        <br>Активность: [[+visitedon:dateAgo]]
    </div>
    <div class="col-md-6">
        Просмотрено тем: [[+views]]<br>
        Создано тем: [[+tickets]]<br>
        Написано комментариев: [[+comments]]<br>
        Рейтинг: [[+rating]]
    </div>
</div>
<hr>

Чанк page_user_info выведет информацию о пользователе:

<img src="[[+photo]]" alt="" /><br>
Имя пользователя: [[+username]]<br>
Полное имя: [[+fullname]]
[[!getTicketsRating? &userId=`[[+internalKey]]`]]

<p>Рейтинг [[+rating]]</p>
<p>Рейтинг тикетов + [[+votes_tickets_up]] / - [[+votes_tickets_down]]</p>
<p>Рейтинг комментариев + [[+votes_comments_up]] / - [[+votes_comments_down]]</p>

Необходимо создать сниппет getTicketsRating для вывода плейсхолдеров рейтинга:

<?php
$userId = intval($userId);
if ($author = $modx->getObject('TicketAuthor',$userId)) $modx->setPlaceholders($author->toArray());
return;

$q = $modx->newQuery('TicketAuthor');
$q->select("*");
$q->where(array(
	'id' => $userId
));
if ($q->prepare() && $q->stmt->execute()) {
    $arr = $q->stmt->fetch();
}
$modx->setPlaceholders($arr);
return;

Наконец, создаем плагин, название любое, у меня userPage

:
<?php
if ($modx->event->name != 'OnPageNotFound') return;

$users_page_id = $modx->getOption('users_page_id', $scriptProperties, '');
$redirect_to_username = $modx->getOption('redirect_to_username', $scriptProperties, 1);
$strict_urls = $modx->getOption('strict_urls', $scriptProperties, 1);

if ($page = $modx->getObject('modResource',intval($users_page_id))) {
    $req = $modx->context->getOption('request_param_alias', null, 'q');
    $url = $_REQUEST[$req];
    $cont_type = $modx->getObject('modContentType',array('name' => 'HTML'));
    $cont_ext = $cont_type->get('file_extensions');
    $cont_isfolder = $page->get('isfolder');
    $page_url = $modx->makeUrl(intval($users_page_id));
    $cont_suf = $modx->getOption('container_suffix', null, '/');
    $url_explode = explode($page_url, $url, 2);

    $position = strpos($url, $page_url);
    if ($position !== false && $position == 0 && count($url_explode) == 2) {
        if (!empty($cont_ext) && $cont_ext != '/') {
            $tmp = explode($cont_ext,$url_explode[1]);
            $url_explode[1] = $tmp[0];
        }
        if (substr($url_explode[1],-1) == '/') $url_explode[1] = substr($url_explode[1],0,-1);
        if (substr($url_explode[1],0,1) == '/') $url_explode[1] = substr($url_explode[1],1);
        

        if ($redirect_to_username && is_numeric($url_explode[1]) && $user = $modx->getObject('modUser', intval($url_explode[1]))) {
            if ($cont_isfolder == 1 && $cont_suf == "/") {
                $page_url = substr($page_url,0,-1);
            }
            $modx->sendRedirect($page_url.'/'.$user->get('username').$cont_type->get('file_extensions'));
        }
        
        if ($strict_urls) {
            $redirect = false;
            if (!empty($cont_ext)) {
                if ($cont_ext == '/' && substr($url,-1) != '/') $redirect = $url.$cont_ext;
                elseif (strpos($url, $cont_ext) === false) $redirect = $url.$cont_ext;
            }
            elseif (substr($url,-1) == '/') $redirect = substr($url,0,-1);
            if ($redirect) $modx->sendRedirect($redirect);
        }
        
        
        if ($user = $modx->getObject('modUser', array('username' => $url_explode[1]))) {
            $modx->setPlaceholders($user->Profile->toArray());
            $modx->setPlaceholders($user->toArray());
            $modx->sendForward($users_page_id);
        }
    }
}
return;

В системный событиях выставляем OnPageNotFound, переходим в параметры, разблокируем по умолчанию, и создаем следующие:

  • redirect_to_username — тип Да/нет — значение: 1. Отвечает за редирект ссылок вида /users/1 -> /users/admin
  • strict_urls — тип Да/нет — значение: 1.Строгий режим ссылок
  • users_page_id — тип Целое — значение: ID страницы, которую мы создавали в самом начале (users).