Личный кабинет пользователя на MODX Login

В этой статье изучим, как в MODX на основании компонента Login создать личный кабинет пользователя, форму для изменения пароля и обновления профиля.
Перед тем, как переходить к изучению этой темы, рекомендуется выполнить действия, приведённые в этих статьях:
Изменение пароля
Изменение пароля будем выполнять на соответствующей странице, созданной нами в предыдущей статье.
Для этого откроем ресурс «Изменение пароля» и поместим в его содержимое форму и вызов сниппета ChangePassword
. С помощью него мы будем выполнять действия, связанные с изменением пароля.
Содержимое ресурса:
[[!ChangePassword?
&submitVar=`change-password`
&placeholderPrefix=`cp.`
&validateOldPassword=`1`
&validate=`nospam:blank`
&reloadOnSuccess=`0`
&successMessage=`Ваш пароль успешно изменён`
&errTpl=`myErrTpl`
]]
<div class="container pt-3">
<div class="card text-dark bg-white mx-auto mb-3" style="max-width: 30rem;">
<div class="card-header">Изменение пароля</div>
<div class="card-body">
[[!+cp.error_message:notempty=`<div class="alert alert-danger" role="alert">[[!+cp.error_message]]</div>`]]
[[!+cp.successMessage:notempty=`<div class="alert alert-success" role="alert">[[!+cp.successMessage:striptags]]</div>`]]
<form class="form" action="[[~[[*id]]]]" method="post">
<input type="hidden" name="nospam" value="">
<div class="mb-3">
<label for="password_old" class="form-label">Старый пароль</label>
<input type="password" class="form-control[[!+cp.error.password_old:notempty=` is-invalid`]]" name="password_old" id="password_old" value="[[+cp.password_old]]">
<div class="invalid-feedback">[[!+cp.error.password_old]]</div>
</div>
<div class="mb-3">
<label for="password_new" class="form-label">Новый пароль</label>
<input type="password" class="form-control[[!+cp.error.password_new:notempty=` is-invalid`]]" name="password_new" id="password_new" value="[[+cp.password_new]]">
<div class="invalid-feedback">[[!+cp.error.password_new]]</div>
</div>
<div class="mb-3">
<label for="password_new_confirm" class="form-label">Введите новый пароль ещё раз</label>
<input type="password" class="form-control[[!+cp.error.password_new_confirm:notempty=` is-invalid`]]" name="password_new_confirm" id="password_new_confirm" value="[[+cp.password_new_confirm]]">
<div class="invalid-feedback">[[!+cp.error.password_new_confirm]]</div>
</div>
<input type="submit" class="btn btn-primary" name="change-password" id="change-password" value="Изменить пароль">
</form>
</div>
</div>
</div>
Вид формы для изменения пароля:

В коде, приведённом выше, форма написана на последней версии Bootstrap. Кроме этого, это касается также других форм, приведённых в этой статье.
Отображение ошибок при валидации данных формы:

Сообщение об успешном смене пароля:

Описание некоторых параметров сниппета ChangePassword
:
Имя параметра | Описание |
---|---|
submitVar | Определяет имя ключа, которое должно присутствовать в $_POST , чтобы ChangePassword начал обрабатывать форму. Если в качестве значения этого параметра указать пустую строку или false , то ChangePassword будет обрабатывать форму при всех POST-запросах. Значение по умолчанию: logcp-submit . |
placeholderPrefix | Префикс, используемый для всех плейсхолдеров, устанавливаемых с помощью этого сниппета. По умолчанию: logcp. . |
validateOldPassword | Определяет, требуется ли пользователю вводить текущий пароль для успешного установления нового. По умолчанию: 1 (т.е. да, необходимо). Если это не нужно, параметру validateOldPassword следует задать значение 0. |
reloadOnSuccess | Необходимо ли страницу перенаправить на саму себя после успешного установления нового пароля. По умолчанию: 1 (т.е. да). Редирект будем осуществляться с параметром GET предотвращающим повторную отправку формы на сервер. Если reloadOnSuccess установить значение 0, то сниппет просто установит соответствующее значение плейсхолдеру successMessage . |
successMessage | Выведет указанное сообщение в плейсхолдер successMessage , если значение параметра reloadOnSuccess равно 0. |
Обновление профиля пользователя
На странице «Редактирование данных» пользователь может изменить данные своего профиля. В данном случае: fullname
(полное имя), phone
(телефон), country
(страна) и website
(веб-сайт). Содержимое ресурса будет включать форму и сниппет UpdateProfile
из пакета Login для её обработки.
Содержимое ресурса:
[[!UpdateProfile?
&validate=`fullname:required`
&reloadOnSuccess=`1`
]]
<div class="container pt-3">
<div class="card text-dark bg-white mx-auto mb-3" style="max-width: 30rem;">
<div class="card-header">Редактирование данных</div>
<div class="card-body">
[[+login.update_success:is=`1`:then=`<div class="alert alert-success" role="alert">[[%login.profile_updated? &namespace=`login` &topic=`updateprofile`]]</div>`:else=`[[+error.message:notempty=`<div class="updprof-error alert alert-danger" role="alert">[[+error.message]]</div>`]]`]]
<form class="form" action="[[~[[*id]]]]" method="post">
<input type="hidden" name="nospam" value="">
<div class="mb-3">
<label for="fullname" class="form-label">[[!%login.fullname? &namespace=`login` &topic=`updateprofile`]]</label>
<input type="text" name="fullname" class="form-control[[+error.fullname:notempty=` is-invalid`]]" id="fullname" value="[[+fullname]]">
<div class="invalid-feedback">[[+error.fullname]]</div>
</div>
<div class="mb-3">
<label for="phone" class="form-label">[[!%login.phone]]</label>
<input type="text" name="phone" class="form-control[[+error.phone:notempty=` is-invalid`]]" id="phone" value="[[+phone]]">
<div class="invalid-feedback">[[+error.phone]]</div>
</div>
<div class="mb-3">
<label for="country" class="form-label">[[!%login.country]]</label>
<input type="text" name="country" class="form-control[[+error.country:notempty=` is-invalid`]]" id="country" value="[[+country]]">
<div class="invalid-feedback">[[+error.country]]</div>
</div>
<div class="mb-3">
<label for="website" class="form-label">[[!%login.website]]</label>
<input type="text" name="website" class="form-control[[+error.website:notempty=` is-invalid`]]" id="website" value="[[+website]]">
<div class="invalid-feedback">[[+error.website]]</div>
</div>
<input type="submit" class="btn btn-primary" value="[[!%login.update_profile]]" name="login-updprof-btn" id="login-updprof-btn">
</form>
</div>
</div>
</div>
Вид формы для обновления данных в профиле:

Описание некоторых параметров сниппета UpdateProfile
:
Имя параметра | Описание |
---|---|
submitVar | Название кнопки submit , которая запускает отправку формы. По умолчанию: login-updprof-btn . |
validate | Список полей для проверки (например: username:required, email:required ). Валидаторы можно указывать цепочкой (например, email:email:required ). |
Личный кабинет пользователя
На странице «Личный кабинет» будем выводить сведения из профиля пользователя, а также кнопки, с помощью которых можно перейти на страницы «Изменения пароля» и «Редактирование данных». Получение данных профиля будем выполнять через сниппет Profile
.
Profile
работает очень просто, он получает данные из базы и устанавливает их в соответствующие плейсхолдеры. Используя плейсхолдеры можно достаточно легко вывести необходимую информацию на странице.
Содержимое ресурса:
[[!Profile? &prefix=`usr.`]]
<div class="container pt-3">
<div class="card text-dark bg-white mx-auto mb-3" style="max-width: 30rem;">
<div class="card-header">Личный кабинет пользователя</div>
<div class="card-body">
<ul class="list-group">
<li class="list-group-item">Имя пользователя: <span class="fw-bold">[[+usr.username]]</span></li>
<li class="list-group-item">Телефон: <span class="fw-bold">[[+usr.phone]]</span></li>
<li class="list-group-item">Email: <span class="fw-bold">[[+usr.email]]</span></li>
<li class="list-group-item">Страна: <span class="fw-bold">[[+usr.country]]</span></li>
<li class="list-group-item">Веб-сайт: <span class="fw-bold">[[+usr.website]]</span></li>
<a class="list-group-item list-group-item-primary list-group-item-action" href="[[~7]]">Изменение пароля</a>
<a class="list-group-item list-group-item-primary list-group-item-action" href="[[~8]]">Редактирование данных</a>
</ul>
</div>
</div>
</div>

В этом HTML-коде вывод списка оформлен с помощью компонента Bootstrap List group.
Описание некоторых параметров сниппета Profile
:
Имя параметра | Описание |
---|---|
prefix | Префикс, используемый для всех плейсхолдеров, которые будут заданы этим сниппетом. |
user | Необязательный параметр. Если задано, то будет использоваться указанный пользователь, а не тот, который в данный момент вошел в систему. Задать пользователя можно посредством id или username . |
useExtended | Если значение true , то также будет установлены в качестве заполнителей все расширенные поля. По умолчанию: 1 (да). |
Следующая тема: Добавление фото пользователю с использованием MODX Login.
так: правильно?
А отчего у меня только вот так работает
а вот так
уже не работает
ну и logout не отрабатывает
хотя
в снипете login выдает
Параметр user является опциональным, его необходимо использовать когда нужно получить профиль не текущего, а какого-то конкретного пользователя.
В MODX пользователь, который авторизован в админке влияет на контекст web. Попробуйте проверить в режиме инкогнито или в другом браузере.
И в Управление словарями MODX не могу их найти, где они установлены, где их можно изменить.https://itchief.ru/assets/uploadify/1/f/0/1f0a1562b54eeaaefd72b56a3ce2316a.png
Для изменения значения лексикона на странице «Управления словарями» необходимо сделать на нём двойной клик и поменять ему текст на другой.
Но вообще-то на странице «Управления словарями», как я прислала скриншот, у меня нет соответствующих записей для страны, телефона и прочих полей.
Получается, пока я не зайду на бэкэнд и не сохраню там что либо, то в полях будут старые данные
У меня вот какая задача — нужно сделать, чтобы пользователи в личном кабинете могли загрузить файлы на сервер, чтобы потом другой пользователь с определенными правами мог их просмотреть/скачать.
Не подскажете, как это можно реализовать
нужно чтобы по адресу mysite.ru/lk/info.html для каждого пользователя была доступна текстовая (или ссылки, картинки) информация, но для каждого пользователя она будет своя, вручную устанавливаемая админом. Причем для каждого пользователя это один и тот же набор полей.
По аналогии, как в личном кабинете каждому пользователю выводится его имя, телефон мне кажется можно завести дополнительные поля, но к самому пользователю эта информация по сути не имеет отношения.
Насколько верно я мыслю или может быть есть другие, более удобные варианты?
И еще желательно, чтобы при изменении поля конкретного пользователя ему уходило информационное письмо.
Получить их можно так:
Для отправки письма при обновлении данных пользователя можно создать плагин на событие OnUserBeforeSave и в нём написать необходимую логику.
Подскажите пожалуйста такой момент.
Если не авторизованный пользователь, переходит по ссылке личного кабинета, ему открывается форма авторизации, что в принципе логично. Но ссылка остаётся личного кабинета а не меняется на страницу авторизации это так и должно быть?
И ещё один нюанс после авторизации на странице Личного кабинета, пользователя перебрасывает на главную страницу сайта, а должно перенаправлять на страницу для авторизованного пользователя. Как это поправить можно?
Для редиректа можно на эти страницы добавить сниппет, который будет проверять «вошел» ли пользователь в определенный контекст, и если нет, то осуществлять редирект.
Код сниппета:
В системных параметрах есть такой ключ unauthorized_page. В нём необходимо указать id ресурса, который нужно выводить пользователям при запросе запрещённых и требующих авторизации ресурсов. По умолчанию он имеет значение 1, поэтому и перебрасывает на главную страницу.
Просто не срабатывает как будто его и нет, в строке также остаётся url личного кабинета (lk).
В принципе меня даже больше смущает не то, что остается url личного кабинета, а то что редирект происходит на главную после авторизации на страницы с url'ом личного кабинета (lk).
Авторизуясь со страницы авторизации, всё срабатывает как должно и мы остаёмся на странице для авторизованного пользователя.
В ключе unauthorized_page у меня стоит не дефолтное значение, а id страницы авторизации.
Какие ещё могут быть варианты?
1) сообщение об ошибке (не указывается какой) появляется в любом случае. даже если потом идет сообщение об успешном изменении пароля. и под строкой старого пароля ВСЕГДА написано что старый пароль неверный.
Это не смотря на то что форма работает и меняет пароль.
2)вне зависимости от количества сообщений об ошибке в самом верху они все одинаковые и не соответствуют подписям под полями форм, они все берутся из одного чанка «ошибка авторизации».
3) откуда вообще берутся все эти сообщения типа «пароли не совпадают»? Если они зашиты в компонент, то не совсем понятно — почему данные сообщения зашиты в логику компонента, а success.message требуют написать самому
Установка сообщений выполнено автором компонента, сообщение об успехе через параметр successMessage. Остальные сообщения берутся из словаря. Их редактирование осуществляется на странице «Управление словарями».
1) Почему у меня выводится только одно значение плейсхолдера с ошибкой вверху вне зависимости от характера ошибки в форме «Ошибка авторизации» Я то уж никак не могу повлиять на этот плейсхолдер…
2) Почему при проверке старого пароля он выдает ошибку, хотя пароль верный и сама программа смены пароля выполняется (поэтому и вверху сохраняется сообщение об ошибке, за которым следует сообщение об успешной авторизации)
Может это по причине, что после установки нового пароля программа сравнивает введенный и ОСТАВШИЙСЯ в форме старый пароль уже с НОВЫМ?!
Вообще на мой взгляд непонятно. почему взаимоисключаются функции сброса формы (перезагрузки) и сообщения об успехе… я бы например сделал лучше это одновременно
Как то я плохо понимаю работу плейсхолдеров…
у меня добавилось вопросов.
не совсем понял как работают поля в UpdateProfile
В Регистрации вроде все сделал — добавил поля через Extended, заполняю их при регистрации, они все попадают в Кабинет.
(кроме select пола, он почему то выдает «0», что то я с HTML не так сделал)
Но вот при редактировании профиля я не могу поменять значения этих добавленных полей. меняю, нажимаю на кнопку и возвращаются значения регистрационные… тыкаюсь как слепой… уже и префиксы пробовал устанавливать зачем то, не помогает — редактируются только изначально существующие поля в чанке, добавленные поля (я там тоже EXTENDED установил и добавил их) не редактируются. Какой смысл тогда в EXTENDED? что я не так делаю.
Итак, резюмирую свои нерешенные проблемы (я пока на локалке, хостинга нет. это мой первый проект, пока не отлажу сайт, смысл заливать его на хост):
1) двойное сообщение о регистрации. Это бы еще ничего, но так же дублируются сообщения при сбросе пароля. а это уже криминал, ибо в них разные ссылки и разные пароли
2) После авторизации и смене пароля в форме возникает ошибка авторизации почему то и сведения о неверном старом пароле ПРИ сообщении об успешной смене пароля. пароль меняется.
3) Не понял как редактировать расширенные поля. Ведь во время регистрации нельзя давать пользователю слишком много полей заполнять — уйдет с сайта, а вот после регистрации через изменение профиля он вполне мог бы добавить данные. Но после регистрации я могу менять сайт, fullname (вообще непонятное мне поле) телефон, адрес, город, страну. Все расширенные поля либо пустые, либо те, которые заполнялись при регистрации — не редактируются… И никаких сообщений об успешном изменении данных не выдается.
По моей логике должна быть ОДИН видимый пункт в меню — ЛИЧНЫЙ КАБИНЕТ. Кликая на него, пользователь уже либо попадает в личный кабинет если он авторизован (проверяется штатным сниппетом компонента isLoggedIn), либо на страницу авторизации. Когда же механизм выхода «зашит» в сниппете LOGIN, непонятно, как его оттуда выудить и вставить в личный кабинет
не обижайтесь, хотя я и не программист по профессии. но очень системный и дотошный, математику много изучал в свое время… все время стремлюсь к оптимизации….Согласитесь, то ШТАТНО кнопка выхода размещена на странице входа, хотя гораздо логичнее ее штатно было разместить на странице профиля… Существующая конфигурация предполагает усложнения структуры ВИДИМОГО меню на один минимум пункт… Или размещение дополнительных элементов в шаблонах… Давайте представим, что у нас только компонент Логин и все… для выхода из меню мы должны будем сделать минимум два пункта меню — видимых — Личный кабинет и Вход… в то время как если бы функция выхода была в сниппете Профайл, мы обошлись бы одним видимым пунктом — Личный кабинет… из него мы попадем и на страницу авторизации, и на страницу регистрации — в зависимости от нашего статуса… из него же мы сразу и выйдем)
давайте рассмотрим пример… Странно
Кнопка «Выйти» не привязана к входу, просто логика выхода реализована в сниппете Login.
Сниппет Profile практически не имеет никакой логики. Он только устанавливает плейсхолдеры, чтобы было очень просто вывести информацию о пользователе.
А как из личного кабинета можно попасть на страницу авторизации или на страницу регистрации в зависимости от статуса. Если пользователь не авторизован, то как можно узнать имеет ли он учётную запись или нет.
Можно сделать и с помощью одной кнопки, например, личный кабинет. Пользователь при нажатию на кнопку, попадает на страницу «Личный кабинет». Если у него нет прав, MODX перенаправляет его на страницу «Авторизация». На данной странице, если у него есть учётная запись, то он вводит логин и пароль, и после аутентификации попадает на страницу «Личный кабинет». Если нет, то, например, нажимает на кнопку «Зарегистрироваться» и походит процедуру регистрации. В итоге в меню всего будет одна кнопка.
При просмотре страницы ссылка id30, а тайтл от главной и редактирование с фронта, тоже редактирует Главную id1 страницу.
Я правильно понял, что листинг кода нужно вставлять банально в Создать — Новый документ?
Прошу помочь. У меня обнаружилось очень загадочное поведение про использовании Profile.
Вот такой код:
выводит содержимое, а при использовании модификатора notempty — нет…
Нонсенс, но тем не менее…
Встречались с таким?
Попробуйте добавить префикс:
Сделайте его не кэшированным:
Делал по инструкции — значит у вас работает, а у меня — нет.
С чем это может быть связано? Хочется понять на будущее)
А в писание используемых параметров user?
А параметр user необходимо указывать тогда, когда Вы хотите получить данные определённого пользователя. Но в данном случае он не нужен, т.к. он по умолчанию возвращает данные текущего пользователя. А это как раз то, что нужно в данном случае.
Очень помогла!
А как привязать к профилю аватарку?
А после вывести ее в комментарии в Тикетах?