Serhii
Товариство, збираємо на розвиток Evolution CMS, долучайтесь! https://send.monobank.ua/jar/A4oeebdkF9
Друзі. Ось банка. Треба ще 5 000 грн, щоб покрити цьогорічні затрати на підтримку Ево. Ну, й було б чудово шось зверху на смаколики.
Serhii
Чесно кажучи вже й соромно якось клянчити. Але колективу повинно бути ще соромніше.
Serhii
Сергій Зможемо темплейтєдітор3 Переробити на sTemplateEditor?))) Я думаю тут багато людей котрі навіть задонатять на це) Треба щоб воно працювало з sLang
Доречі, тут така ідея, що Темплейт Едітор буде не потрібен. Планується, що адмінка буде збиратись компонентно. Дімас готує щось надзвичайно смачне.
𝓔𝓾𝓰𝓮𝓷𝓮
Товариство, збираємо на розвиток Evolution CMS, долучайтесь! https://send.monobank.ua/jar/A4oeebdkF9
Хлопці та дівчата) Давайте поднажмем трохи Не треба забувати. Давайте на розвиток та підтримку! Я думаю що скоро від оновлення ЕВИ ми всі будемо в шоці ;)
Serhii
Та біда, що я не поспіваю за думками. Потроху губляться круті ідеї.
Artur
https://dev.mysql.com/blog-archive/mysql-character-sets-unicode-and-uca-compliant-collations/ в MySQL вже давно рекомендованими є - utf8mb4_0900_* - utf8mb4_bin тут пояснення, чому не треба юзати general_ci https://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci може нам пофіксити в інсталяторі на рекомендовані? якусь регресію це навряд чи викличе
Serhii
Он Дімас вже від мене частину роботи чекає. @Dmi3yy пм'ятаю... Ще в процесі...
Artur
нормально працює з усіма мовами, тому й треба
Artur
Так, теж читав це. Але в інсталяторі поки що не треба. Я ще в процесі дорослого інсталятора через артісан. Там вже й нормальне кодування встановимо.
можна мій фікс змержити, бо залежність від jQuery з cdn в 2025, скрипти, що не працюють з локальною CSP, стилі, ще й різні в локальних CSS замість класів для приховування елементів, та inline CSS в транслейшнах під час інсталяції - це таке собі. https://github.com/evolution-cms/evolution/pull/2155/files чи хоча б врахувати це
Artur
collation рекомендований, доречі, можна отримувати без хардкоду (на випадок якщо він зміниться, чи щоб уникнути ситуації, коли він буде в MySQL але його викинуть, наприклад, з MariaDB) https://dev.mysql.com/doc/refman/8.4/en/charset-mysql.html
Artur
дякую. Ще поки писав цей фікс - помітив в нас HTTPS_PORT як константу. Це для чого? Дефолтний завжди буде 443, так само як для HTTP 80. якщо ж треба оверрайд (запустити modx на якомусь порті, але ми не довіряємо $_SERVER['SERVER_PORT']) - то виникає питання, чи це порт, який бачить браузер (і використовується, наприклад, в повних URL в локальних посиланнях), чи це для тих, хто забуде що це 443, чи це порт, на якому слухає безпосередньо сервер, на якому крутиться наш evo (а він може бути в докері, за reverse proxy тощо)?
Artur
ще був момент в інсталяторі щодо перекладів - https://github.com/evolution-cms/evolution/issues?page=2 тут багато тікетів відкрито на відсутність перекладів. їх реально немає, але зараз не проблема нагенерувати AI та бути певними що там не буде якоїсь дичини. але є момент - в install/src/lang/uk.inc.php крім, власне, перекладів, ставиться локаль - setlocale (LC_ALL, 'uk_UA.UTF-8'); причому саме LC_ALL, не LC_LANG, що впливає на форматування валюти, дат тощо. може цю логіку звідти прибрати, бо це ж файл перекладу?
Serhii
Так, треба прибрати.
Artur
https://github.com/evolution-cms/evolution/pull/2156 а це команда, що дозволить пофіксити https://github.com/evolution-cms/evolution/issues/853 та й взагалі, сподіваюсь, корисна на майбутнє See stats of missing keys in user overrides dir manager/includes/lang/override/ php artisan translations:sync See stats of missing keys in system dirs (for core developers) manager/includes/lang/country/ manager/includes/lang/errormsg/ install/src/lang/ php artisan translations:sync --core Write missing keys php artisan translations:sync --core --write Write missing keys sorted php artisan translations:sync --core --write --sort Same as above but change base language from en to uk php artisan translations:sync --core --write --sort --base=uk
𝓔𝓾𝓰𝓮𝓷𝓮
@fav431 Спробуй так: Контролер: SitemapController.php <?php namespace EvolutionCMS\Main\Controllers; class SitemapController extends BaseController { public function setData() { $languages = evo()->getConfig('s_lang_front'); // Масив мов з site_url у ключі 'link' $docs = evo()->runSnippet('DocLister', [ 'parents' => 0, 'depth' => 10, 'showParent' => 1, 'tpl' => '', 'urlScheme' => 'full', 'api' => 1 ]); $sitemap = []; // 👉 Додаємо головну сторінку (перша в списку) $home = [ 'url' => rtrim($languages['uk']['link'], '/'), // українська — основна 'editedon' => date('c'), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $home['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') ]; } $sitemap[] = $home; // 👉 Додаємо всі інші сторінки foreach ($docs as $doc) { $alias = ltrim(parse_url($doc['url'], PHP_URL_PATH), '/'); if ($alias === '') { continue; // пропускаємо головну, бо вона вже є } $entry = [ 'url' => rtrim($languages['uk']['link'], '/') . '/' . $alias, 'editedon' => date('c', $doc['editedon']), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $entry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') . '/' . $alias ]; } $sitemap[] = $entry; } $this->data['sitemap'] = $sitemap; } }
𝓔𝓾𝓰𝓮𝓷𝓮
В шаблоні (views/sitemap.blade.php) встав той самий XML: <?php header('Content-Type: application/xml; charset=utf-8'); echo '<?xml version="1.0" encoding="UTF-8"?>'; ?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> @foreach ($sitemap as $page) <url> <loc>{{ $page['url'] }}</loc> @foreach ($page['alternates'] as $alt) <xhtml:link rel="alternate" hreflang="{{ $alt['lang'] }}" href="{{ $alt['url'] }}" /> @endforeach <lastmod>{{ $page['editedon'] }}</lastmod> </url> @endforeach </urlset>
Yevhenii
@fav431 Спробуй так: Контролер: SitemapController.php <?php namespace EvolutionCMS\Main\Controllers; class SitemapController extends BaseController { public function setData() { $languages = evo()->getConfig('s_lang_front'); // Масив мов з site_url у ключі 'link' $docs = evo()->runSnippet('DocLister', [ 'parents' => 0, 'depth' => 10, 'showParent' => 1, 'tpl' => '', 'urlScheme' => 'full', 'api' => 1 ]); $sitemap = []; // 👉 Додаємо головну сторінку (перша в списку) $home = [ 'url' => rtrim($languages['uk']['link'], '/'), // українська — основна 'editedon' => date('c'), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $home['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') ]; } $sitemap[] = $home; // 👉 Додаємо всі інші сторінки foreach ($docs as $doc) { $alias = ltrim(parse_url($doc['url'], PHP_URL_PATH), '/'); if ($alias === '') { continue; // пропускаємо головну, бо вона вже є } $entry = [ 'url' => rtrim($languages['uk']['link'], '/') . '/' . $alias, 'editedon' => date('c', $doc['editedon']), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $entry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') . '/' . $alias ]; } $sitemap[] = $entry; } $this->data['sitemap'] = $sitemap; } }
Дякую.Та тут ще є трохи харду, я трохи допишу ще, як до десктопу доберусь
Yevhenii
@fav431 Спробуй так: Контролер: SitemapController.php <?php namespace EvolutionCMS\Main\Controllers; class SitemapController extends BaseController { public function setData() { $languages = evo()->getConfig('s_lang_front'); // Масив мов з site_url у ключі 'link' $docs = evo()->runSnippet('DocLister', [ 'parents' => 0, 'depth' => 10, 'showParent' => 1, 'tpl' => '', 'urlScheme' => 'full', 'api' => 1 ]); $sitemap = []; // 👉 Додаємо головну сторінку (перша в списку) $home = [ 'url' => rtrim($languages['uk']['link'], '/'), // українська — основна 'editedon' => date('c'), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $home['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') ]; } $sitemap[] = $home; // 👉 Додаємо всі інші сторінки foreach ($docs as $doc) { $alias = ltrim(parse_url($doc['url'], PHP_URL_PATH), '/'); if ($alias === '') { continue; // пропускаємо головну, бо вона вже є } $entry = [ 'url' => rtrim($languages['uk']['link'], '/') . '/' . $alias, 'editedon' => date('c', $doc['editedon']), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $entry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') . '/' . $alias ]; } $sitemap[] = $entry; } $this->data['sitemap'] = $sitemap; } }
Як обіцяв, відписую по результатам тесту. Цього всього, що в цитованому нема в $languages, бо в s_lang_front не масив, а простий рядок виду 'uk,en'
Yevhenii
@fav431 Спробуй так: Контролер: SitemapController.php <?php namespace EvolutionCMS\Main\Controllers; class SitemapController extends BaseController { public function setData() { $languages = evo()->getConfig('s_lang_front'); // Масив мов з site_url у ключі 'link' $docs = evo()->runSnippet('DocLister', [ 'parents' => 0, 'depth' => 10, 'showParent' => 1, 'tpl' => '', 'urlScheme' => 'full', 'api' => 1 ]); $sitemap = []; // 👉 Додаємо головну сторінку (перша в списку) $home = [ 'url' => rtrim($languages['uk']['link'], '/'), // українська — основна 'editedon' => date('c'), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $home['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') ]; } $sitemap[] = $home; // 👉 Додаємо всі інші сторінки foreach ($docs as $doc) { $alias = ltrim(parse_url($doc['url'], PHP_URL_PATH), '/'); if ($alias === '') { continue; // пропускаємо головну, бо вона вже є } $entry = [ 'url' => rtrim($languages['uk']['link'], '/') . '/' . $alias, 'editedon' => date('c', $doc['editedon']), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $entry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') . '/' . $alias ]; } $sitemap[] = $entry; } $this->data['sitemap'] = $sitemap; } }
А ще отут $docs не форічіться, бо це json після доклістера, бо вивід апі=>1, але це не так критично, якщо пропустити через json_decode
𝓔𝓾𝓰𝓮𝓷𝓮
То мені треба поставити Сленг, та покопатися
𝓔𝓾𝓰𝓮𝓷𝓮
в контролері <?php namespace EvolutionCMS\Main\Controllers; class SitemapController extends BaseController { public function setData() { // 🔹 Витягуємо мови $langCodes = explode(',', evo()->getConfig('s_lang_front')); $defaultLang = trim($langCodes[0]); // перша мова — основна // 🔹 Формуємо масив мов із посиланнями $languages = []; foreach ($langCodes as $code) { $code = trim($code); $languages[$code] = [ 'code' => $code, 'link' => $code === $defaultLang ? evo()->getConfig('site_url') // без префікса : evo()->getConfig('site_url') . $code . '/' // з префіксом ]; } // 🔹 Отримуємо список документів як JSON і декодуємо $json = evo()->runSnippet('DocLister', [ 'parents' => 0, 'depth' => 10, 'showParent' => 1, 'tpl' => '', 'urlScheme' => 'full', 'api' => 1 ]); $docs = json_decode($json, true) ?: []; $sitemap = []; // 🔹 Додаємо головну сторінку $homeEntry = [ 'url' => rtrim($languages[$defaultLang]['link'], '/'), 'editedon' => date('c'), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $homeEntry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') ]; } $sitemap[] = $homeEntry; // 🔹 Додаємо інші сторінки foreach ($docs as $doc) { $alias = ltrim(parse_url($doc['url'], PHP_URL_PATH), '/'); if ($alias === '') { continue; // пропускаємо головну } $entry = [ 'url' => rtrim($languages[$defaultLang]['link'], '/') . '/' . $alias, 'editedon' => date('c', $doc['editedon']), 'alternates' => [] ]; foreach ($languages as $code => $lang) { $entry['alternates'][] = [ 'lang' => $code, 'url' => rtrim($lang['link'], '/') . '/' . $alias ]; } $sitemap[] = $entry; } $this->data['sitemap'] = $sitemap; } }
𝓔𝓾𝓰𝓮𝓷𝓮
і сам блейд <?php header('Content-Type: application/xml; charset=utf-8'); echo '<?xml version="1.0" encoding="UTF-8"?>'; ?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> @foreach ($sitemap as $page) <url> <loc>{{ $page['url'] }}</loc> @foreach ($page['alternates'] as $alt) <xhtml:link rel="alternate" hreflang="{{ $alt['lang'] }}" href="{{ $alt['url'] }}" /> @endforeach <lastmod>{{ $page['editedon'] }}</lastmod> </url> @endforeach </urlset>
𝓔𝓾𝓰𝓮𝓷𝓮
Можливо навіть краще буде переробити DLSitemap Назвати його sDLSitemap
Serhii
Можливо навіть краще буде переробити DLSitemap Назвати його sDLSitemap
Вважаю, що нема сенсу. Як попадеться мені в роботу мультимовний сайт, то модуль sSeo буде допрацьовано під мультимову. Наразі працює генерація сайтмап під мультисайт.
𝓔𝓾𝓰𝓮𝓷𝓮
Нажаль мені вже 43
Ghostery
на щастя)
Gunduz
TinyMCE4 не реагує на CSS. Що робити? Хтось стикався такою проблемою?
Gunduz
Gunduz
Maxa
site/css/bootstrap.min.css браузер бачить ці шляхи?
Gunduz
Maxa
як варіант - завантажувати ці файлі через плагін вішати на OnDocFormRender $output = '<link rel="stylesheet" type="text/css" href="css/шлях до файлу">'; $modx->Event->output($output);
Gunduz
це допомогло
Artur
Друзі, запропонуйте віджет в адмінку замість цього застарілого.
Зробити там textarea з кнопкою - поле вводу для AI, та під'єднати до неї будь-який опенсорс JS MCP клієнт https://modelcontextprotocol.io/clients . (хто не знає, що таке MCP і навіщо - https://modelcontextprotocol.io/faqs ) Зробити MCP сервер - втягнути ларавелівський MCP SDK https://github.com/php-mcp/laravel?tab=readme-ov-file#content-management , Ну і власне зробити там базові команди - пошук по контенту, wildcards для вкладених ресурсів, створити сторінку, CRUD медіафайли, згенерувати поля для SEO тощо. Тоді можна буде зайти в адмінку і просто написати в цьому віджеті (або навіть сказати, якщо до кнопки додати хоча б браузерне розпізнавання голосового вводу) команду - скороти вдвічі опис товару №123, прибери бекграунд тощо, і він це зробить із коробки з саме цим конкретним сайтом на Evo, бо клієнт та сервер будуть поєднані єдиною авторизацією.
Віталій Пушкарьов 🇺🇦
Зробіть тестову виплату у доларах. Бо не завжди проходить платіж у 500 $ та вище.
Віталій Пушкарьов 🇺🇦
Реквізити у групі. На підтримку платформи і розробників.
Serhii
Друзі, а тут хтось робив здається кукі GDPR. Можете поділитись кодом?
𝓔𝓾𝓰𝓮𝓷𝓮
Тільки хотів відповисти)
Serhii
Та ну тих спамерів нахрін. Я одразу баню за таку чухню.
Alex
Та ну тих спамерів нахрін. Я одразу баню за таку чухню.
Нє, там питання були, просто людина певно розібралась
Serhii
Значить я пропустив.
𝓔𝓾𝓰𝓮𝓷𝓮
Вітаю! Колись тут писав про антиспам по формлістеру, що хочу протестувати, як робив на МОДИКС, але довблюсь вже сутки, не блокуется відправка Може у когось є приклад? Зараз роблю так: 'prepare' => 'CheckSpamTimeFL', 'prepareProcess' => 'CheckCookieTrusted', 'prepareAfterProcess' => 'SendToTelegram', сніппет CheckSpamTimeFL if ($FormLister->isSubmitted()) { $flag = false; $now = microtime(true); if ((isset($_SESSION['now'])) && (($now - $_SESSION['now']) > 5)) { $flag = true; } $FormLister->setValid($flag); } else { $_SESSION['now'] = microtime(true); } А сніппет CheckCookieTrusted return function ($FormLister, $fields) { $cookie = $_COOKIE['spam_check'] ?? null; if (!$cookie || strpos($cookie, 'trusted_user_') !== 0) { $FormLister->addMessage('global', 'Форма недоступна. Перезавантажте сторінку.'); return false; } return true; }; Може хтось вже робив?
Serhii
Нажаль не робив такого. Але є ідея створити щось на кшталт модуль sForms на заміну формлістера. Можете накидати ідей по функціоналу.
Dmytro
Юзав завжди відправку форми через js аяксом і це вроді як від ботів допомогало 3 роки назад але може щось змінилось з того часу)
Serhii
Ідея зробити обгортку для формування форми. Я для комерца написав нормальний джс з валідаціями та підсвіткою невалідних полів. Тож думаю щось подібне зав'язати для форм. Наприклад зворотній зв'зок є всюди. Плюс часто забувають CSRF токен ставити...
Serhii
Ото ж і питаю ідей, що можна передбачити на перед.
𝓔𝓾𝓰𝓮𝓷𝓮
Я ще не самурай) Я тільки вчуся)))
𝓔𝓾𝓰𝓮𝓷𝓮
Вітаю! Колись тут писав про антиспам по формлістеру, що хочу протестувати, як робив на МОДИКС, але довблюсь вже сутки, не блокуется відправка Може у когось є приклад? Зараз роблю так: 'prepare' => 'CheckSpamTimeFL', 'prepareProcess' => 'CheckCookieTrusted', 'prepareAfterProcess' => 'SendToTelegram', сніппет CheckSpamTimeFL if ($FormLister->isSubmitted()) { $flag = false; $now = microtime(true); if ((isset($_SESSION['now'])) && (($now - $_SESSION['now']) > 5)) { $flag = true; } $FormLister->setValid($flag); } else { $_SESSION['now'] = microtime(true); } А сніппет CheckCookieTrusted return function ($FormLister, $fields) { $cookie = $_COOKIE['spam_check'] ?? null; if (!$cookie || strpos($cookie, 'trusted_user_') !== 0) { $FormLister->addMessage('global', 'Форма недоступна. Перезавантажте сторінку.'); return false; } return true; }; Може хтось вже робив?
Трохи переробив, подивлюся як воно буде, якщо що, то треба становитися на бік самурая)) if ($FormLister->isSubmitted()) { $cookie = $_COOKIE['spam_check'] ?? ''; if ($cookie && strpos($cookie, 'trusted_user_') === 0) { $flag = true; } else { $flag = false; // Лог file_put_contents(MODX_BASE_PATH . 'assets/logs/cookie_block.log', date('Y-m-d H:i:s') . " | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '-') . " | COOKIE: " . $cookie . "\n", FILE_APPEND ); } $FormLister->setValid($flag); }
Serhii
Я теж не самурай, але намагаюсь. У нас тут Дмитро самий крутий.
𝓔𝓾𝓰𝓮𝓷𝓮
Во наловив вже Лізуть як блохи до моєї собаки
Serhii
Во наловив вже Лізуть як блохи до моєї собаки
Чесно кажучи використовувати формлістер не рекомендую. Мені через нього кібер безпека однієї всім відомої компанії хакнула адмінку. Саме через Формлістер.
𝓔𝓾𝓰𝓮𝓷𝓮
Їханий бабай.... Наступного тижня буду дивитися у бік самурая Капець
Serhii
Я роблю так. До прикладу.
Serhii
Форма: <form action="{{route('contact.send')}}" class="contacts__form form-wrap" method="POST"> <div class="inputs__wrapper"> <div class="input__block"> @isset($_SESSION['fields']['first_name']['error'])<span class="error">{{$_SESSION['fields']['first_name']['error'] ?? ''}}</span>@endif <input type="text" name="first_name" value="{{$_SESSION['fields']['first_name']['old'] ?? ''}}" class="input-reset form__input" placeholder="First name"> <label class="form__label"><span>First Name</span></label> </div> <div class="input__block"> @isset($_SESSION['fields']['last_name']['error'])<span class="error">{{$_SESSION['fields']['last_name']['error'] ?? ''}}</span>@endif <input type="text" name="last_name" value="{{$_SESSION['fields']['last_name']['old'] ?? ''}}" class="input-reset form__input" placeholder="Last name"> <label class="form__label"><span>Last Name</span></label> </div> <div class="input__block"> @isset($_SESSION['fields']['contact_tel']['error'])<span class="error">{{$_SESSION['fields']['contact_tel']['error'] ?? ''}}</span>@endif <input type="tel" name="contact_tel" value="{{$_SESSION['fields']['contact_tel']['old'] ?? ''}}" class="input-reset form__input" placeholder="Contact Phone"> <label class="form__label"><span>Contact Phone</span></label> </div> </div> <div class="inputs__two-col"> <div class="input__block"> @isset($_SESSION['fields']['contact_email']['error'])<span class="error">{{$_SESSION['fields']['contact_email']['error'] ?? ''}}</span>@endif <input type="email" name="contact_email" value="{{$_SESSION['fields']['contact_email']['old'] ?? ''}}" class="input-reset form__input" placeholder="E-Mail"> <label class="form__label"><span>E-Mail</span></label> </div> <div class="select-field"> @isset($_SESSION['fields']['service']['error'])<span class="error">{{$_SESSION['fields']['service']['error'] ?? ''}}</span>@endif <span>Type of service</span> <select name="service"> <option value="hotel" @if(!isset($_SESSION['fields']['service'])) selected @endif @if(($_SESSION['fields']['service']['old'] ?? '') == 'hotel') selected @endif>Hotel</option> <option value="flight" @if(($_SESSION['fields']['service']['old'] ?? '') == 'flight') selected @endif>Flight</option> <option value="tour" @if(($_SESSION['fields']['service']['old'] ?? '') == 'tour') selected @endif>Tour</option> </select> </div> </div> <h5 class="h5-title">Your comment</h5> <textarea rows="4" placeholder="Notes" name="comment">{{$_SESSION['fields']['comment']['old'] ?? ''}}</textarea> @isset($_SESSION['fields']['comment']['error'])<span class="error">{{$_SESSION['fields']['comment']['error'] ?? ''}}</span>@endif <button class="btn-reset btn-primary">Send your message</button> <input type="text" name="extra_field" id="extra_field" style="display:none;"> <input type="hidden" name="{{$dynamicFieldName ?? ''}}" value="{{$dynamicFieldValue ?? ''}}"> </form>
𝓔𝓾𝓰𝓮𝓷𝓮
Нажаль не робив такого. Але є ідея створити щось на кшталт модуль sForms на заміну формлістера. Можете накидати ідей по функціоналу.
Є ідея відразу зробити модуль для адмінки Де можна дивитися записи Загружати в єкселіо
Serhii
Контроллер: <?php namespace EvolutionCMS\Main\Controllers; use Illuminate\Support\Facades\Validator; use Seiger\sArticles\Models\sArticle; class ContactsController extends BaseController { public function noCacheRender() { parent::noCacheRender(); if (request()->method() != 'POST') { $this->data['dynamicFieldName'] = $_SESSION['dynamicFieldName'] = 'extra_' . md5(time()); $this->data['dynamicFieldValue'] = $_SESSION['dynamicFieldValue'] = md5(uniqid(mt_rand(), true)); $info = data_is_json(evo()->documentObject['info'][1], true); if ($info) { $info = $info['fieldValue']; } $this->data['info'] = $info; } } }
Serhii
Роут (core/custom/routes.php): Route::post('contact/send', [OrderHelperController::class, 'sendContactForm'])->name('contact.send');
Serhii
Метод в хелпері: public function sendContactForm() { if (isset($_SESSION['fields'])) unset($_SESSION['fields']); if (isset($_SESSION['success'])) unset($_SESSION['success']); if (isset($_SESSION['error'])) unset($_SESSION['error']); $dynamicFieldName = $_SESSION['dynamicFieldName']; $dynamicFieldValue = $_SESSION['dynamicFieldValue']; if (request()->input('extra_field') !== 'human' || request()->input($dynamicFieldName) !== $dynamicFieldValue) { $_SESSION['error'] = 'Form submission failed.'; return redirect()->back(); } $validator = Validator::make(request()->all(), [ 'first_name' => 'required', 'last_name' => 'required', 'contact_tel' => 'required', 'contact_email' => 'required|email', 'service' => 'required', 'comment' => 'required', ], [ 'first_name.required' => 'The First Name field is required.', 'last_name.required' => 'The Last Name field is required.', 'contact_tel.required' => 'The Contact Phone field is required.', 'contact_email.required' => 'The E-Mail field is required.', 'contact_email.email' => 'The E-Mail must be a valid email address.', 'service.required' => 'The Type of service field is required.', 'comment.required' => 'The Comment field is required.', ]); foreach ($validator->getData() as $field_name => $value) { $_SESSION['fields'][$field_name]['old'] = $value; } if ($validator->fails()) { foreach ($validator->messages()->getMessages() as $field_name => $messages) { $_SESSION['fields'][$field_name]['error'] = $messages[0]; } $_SESSION['error'] = 'Form submission failed.'; return redirect()->back(); } $message = view('mails.feedback', $validator->getData())->render(); $param = array(); $param['from'] = evo()->getConfig('site_name') . '<' . $validator->validated()['contact_email'] . '>'; $param['subject'] = 'Contact us via ' . $validator->validated()['service']; $param['body'] = $message; $param['to'] = evo()->getConfig('sset_email'); $param['type'] = 'html'; Log::info("sendContactForm:\n" . var_export($param, TRUE)); evo()->sendmail($param); $_SESSION['success'] = 'Your message has been sent.'; if (isset($_SESSION['fields'])) unset($_SESSION['fields']); return redirect()->back(); }
Serhii
І джаваскриптина в футері: <script> const forms = ['request', 'send-review']; const actions = ["{{route('request.send')}}", "{{route('review.send')}}"]; for (let j = 0; j < forms.length; j++) { document.getElementById(forms[j])?.addEventListener("submit", function(e) { e.preventDefault(); formSend(j); }); } function formSend(indx) { let form = document.getElementById(forms[indx]) fetch(actions[indx], { method: "POST", cache: "no-store", body: new FormData(form) }).then((response) => { return response.json(); }).then((data) => { document.querySelectorAll("#" + forms[indx] + " .error").forEach(function (i) { i.innerText = ''; }); if (typeof(data['errors']) != "undefined" && data['errors'] !== null) { for (let k in data['errors']) { document.querySelector("#" + forms[indx] + ' [name="'+k+'"]').parentNode.querySelector('span.error').innerText = data['errors'][k][0]; } } if (data.status == true) { if (typeof(data.redirect) != "undefined" && data.redirect !== null) { window.location.href = data.redirect; } if (typeof(data.message) != "undefined" && data.message.length > 1) { document.querySelector("[data-graph-target=\"thanks\"] .graph-modal__content p").innerText = data.message; } document.querySelector('.graph-modal.is-open').querySelector('.js-modal-close').click(); window.openModalId('thanks'); } }).catch(function(error) { console.error("Request failed", error, "."); }); } </script>
Serhii
То я мабуть таки самурай.
Serhii
Цей приклад з реального проєкта.
𝓔𝓾𝓰𝓮𝓷𝓮
Цей приклад з реального проєкта.
Дякую! Це буде як приклад для мене
ㅤ
Приветствую, не подскажите можно перенести данные из другой CMS в эту?
Eintipper
І джаваскриптина в футері: <script> const forms = ['request', 'send-review']; const actions = ["{{route('request.send')}}", "{{route('review.send')}}"]; for (let j = 0; j < forms.length; j++) { document.getElementById(forms[j])?.addEventListener("submit", function(e) { e.preventDefault(); formSend(j); }); } function formSend(indx) { let form = document.getElementById(forms[indx]) fetch(actions[indx], { method: "POST", cache: "no-store", body: new FormData(form) }).then((response) => { return response.json(); }).then((data) => { document.querySelectorAll("#" + forms[indx] + " .error").forEach(function (i) { i.innerText = ''; }); if (typeof(data['errors']) != "undefined" && data['errors'] !== null) { for (let k in data['errors']) { document.querySelector("#" + forms[indx] + ' [name="'+k+'"]').parentNode.querySelector('span.error').innerText = data['errors'][k][0]; } } if (data.status == true) { if (typeof(data.redirect) != "undefined" && data.redirect !== null) { window.location.href = data.redirect; } if (typeof(data.message) != "undefined" && data.message.length > 1) { document.querySelector("[data-graph-target=\"thanks\"] .graph-modal__content p").innerText = data.message; } document.querySelector('.graph-modal.is-open').querySelector('.js-modal-close').click(); window.openModalId('thanks'); } }).catch(function(error) { console.error("Request failed", error, "."); }); } </script>
я останній раз робив через гугл рекапчу (для юзера вона прихована) типу якщо у по версії гугла спам скор виский, то форма і не відішле нічого (хоча юзер думатиме що відіслав). якось так.
𝓔𝓾𝓰𝓮𝓷𝓮
Гугляк не дуже файно (імхо) Але дякую за підказку
𝓔𝓾𝓰𝓮𝓷𝓮
Шо це за гівно?
Serhii
Таке гівно зразу в бан.
Бавовнятко
Прокинулись)То що за скрін?
Нирмаланатх
Доброго дня
Нирмаланатх
Підкажіть як відновити пароль