Boilerplate. Базовая настройка сайта.
Список устанавливаемых дополнений
Ресурсы
Плагины
Системные настройки
boilerplate_tpl_css ( шаблон загрузки css ) =
boilerplate_hide_vtabs_tv = нет
Другое
- FormIt (обработка форм, отправка заявок на электронную почту)
- MIGX (для создания табличек у ресурсов)
- TinyMCE Rich Text Editor (визуальный редактор)
- translit (автоматическая транслитерация адресов страниц)
- SEO Tab (настройка страницы для поисковых систем)
- SEO Pro (настройка шаблона сайта в поисковой выдачи)
- Ace (лучший редактор кода)
- AjaxForm (отправка форм через Ajax)
- controlErrorLog (управление журналом ошибок)
- MinifyX (автоматизированное сжатие скриптов и стилей сайта)
- mixedImage (смешанная загрузка файла)
- phpThumbOn (для изменения размера и сжатия изображения)
- pdoTools (быстрая выборка страниц и пользователей сайта)
- tinyCompressor (автоматическая оптимизация загружаемых файлов)
Ресурсы
- Главная
- Сервис
- 403 (страница ошибки 403 «Доступ запрещен»)
- 404 (страница ошибки 404 «Документ не найден»)
- 503 (страница «Сайт недоступен»)
- Карта сайта (HTML)
- SiteMap (sitemap.xml)
- Robots (robots.txt)
- head (файловый элемент)
Плагины
- Boilerplate
- привязывается CSS-файл к странице редактирования ресурсов (assets/boilerplate/mgr/manager.css)
- сжимает вывод html для Google (можно отменить в системной настройке boilerplate_compress_output_html)
- возможность спрятать вертикальный таб для tv(системная настройка boilerplate_hide_vtabs_tv)
- модификаторы fenom:
- alias (транслитерация строки)
- m2 (модифицирует строку m2 в квадратные метры)
- phone (убирает лишние символы)
- table (модифицирует значение поля table в таблицу)
- managerBreadCrumbs (хлебные крошки в админке)
Системные настройки
CORE
- allow_multiple_emails = Да (чтобы у каждого пользователя была своя электронная почта)
- friendly_alias_realtime = Да (генерация псевдонима в реальном времени)
- friendly_urls = Да (включение дружественных URL)
- friendly_urls_strict = Да (строгий режим)
- publish_default = Да (по умолчанию ресурс создаётся опубликованным)
- use_alias_path = Да (чтобы в URL учитывался псевдоним родителя, а не его замороженный URL)
- friendly_alias_translit = russian (настройка транслитерации)
- resource_tree_node_name = menutitle (чтобы названия ресурсов в дереве были покороче)
- resource_tree_node_tooltip = alias (чтобы можно было понять, какой у ресурса адрес)
- locale = ru_RU.utf8 (для генерации даты с названиями месяцев)
- request_method_strict = Да (отключение доступа к странице по id)
- unauthorized_page = {id} (id 403 страницы)
- error_page_header = HTTP/1.0 404 Not Found (заголовок для 404 ошибки)
- error_page = {id} (id 404 страницы)
- site_unavailable_page = {id} (id 503 страницы)
PDOTOOLS
- pdotools_fenom_default = Да (использование Fenom в чанках)
- pdotools_fenom_modx = Да (разрешаем MODX в Fenom)
- pdotools_fenom_parser = Да (использование Fenom на страницах)
- pdotools_elements_path = {core_path}/ (для загрузки файловых элементов)
TINYCOMPRESSOR
- tinycompressor_tinypng_upload_enable = Да (сжимает загружаемые изображения)
TINYMCERTE
- tinymcerte.plugins = advlist autolink lists modximage charmap print preview anchor visualblocks searchreplace code fullscreen insertdatetime media table contextmenu paste modxlink textcolor colorpicker
- tinymcerte.toolbar1 = undo redo | styleselect | backcolor forecolor bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image
BOILERPLATEboilerplate_compress_output_html = Да (сжимает вывод html для Google)
boilerplate_tpl_css ( шаблон загрузки css ) =
<link rel="preload" href="[[+file]]" as="style" onload="this.onload=null;this.rel='stylesheet'">
boilerplate_tpl_js (шаблон загрузки js) = <link rel="preload" href="[[+file]]" as="script"><script src="[[+file]]" defer></script>
boilerplate_social = [[«behance»,«Behance»], [«dribbble», «Dribbble»], [«facebook*-f»,«facebook*»], ...] (список соц. сетей)boilerplate_hide_vtabs_tv = нет
Другое
- Установка HTTP заголовков
- X-Frame-Options:deny
- X-XSS-Protection:1;mode=block
- X-Content-Type-Options:nosniff
- Referrer-Policy:no-referrer
- Cache-Control: max-age=31536000, must-revalidate
- Удаляется файл changelog.txt, чтобы убрать сообщение о том, что безопасность сайта не в порядке
- Переименовываются файлы ht.access в корне и в папке /core/, чтобы заработали дружественные URL
- Меняем контент главного шаблона и делаем его статичным
- Хуки для minifyX
- libs.php (для загрузки библиотек)
- ms2 (инициализации minishop2, для поддержки асинхронной загрузке скриптов)
*Meta, которой принадлежат facebook и instagram признана экстремистской в России
Поблагодарить автора
Отправить деньги
Комментарии: 27
Удаляется файл changelog.txt, чтобы убрать сообщение о том, что безопасность сайта не в порядкеДля дружественных URL — htaccess в корне сайта.
Переименовываются файлы ht.access в корне и в папке /core/, чтобы заработали дружественные URL
В htaccess в папке core закрывает доступ извне, и как раз убирает предупреждение, которое вы убираете удалением файла :facepalm:
Убирает предупреждение для серверов на apache, а вот для серверов на ngnix, которых большинство — фокус не удастся, там только текстовый файл физически удалять
Можно закрыть через конфигурацию хоста в nginx
Но скрывать потенциальную проблему — лучший способ.
Но скрывать потенциальную проблему — лучший способ.
на шаред хостингах иногда нет доступа к конфигуратору nginx, и удаление changelog — единственное решение убрать оповещение о нарушении безопасности
Можно настроить под себя? Удалить что то из списка и добавить свое?
На данный момент нет.
Можно сделать свою собственную сборку на основе siteExtra. Я сейчас сайты на modx делаю именно так, сделал свою базовую сборку и в ней пишу всю основу для создания чистого сайта. Сайт на такой сборке можно легко пустить в работу, а все фундаментальные изменения делать именно в установщике. Это позволит нам избежать правок в админке и все наши изменения будут жить в скрипте. Ну и плюс это опыт по работе с modx/компонентами программно.
Так же я интегрировал в свою сборку gulp (для внесения изменений в верстку на лету). Ну это мне просто так удобно, когда верстка рядом с кодом лежит.
В будущем планирую этот билдер выложить в открытый доступ, но сейчас есть 2 небольшие проблемы, вернее одна небольшая, с ней сам справлюсь — а вот вторая большая. Мне нужна помощь в написании ресолвера, который будет устанавливать пакеты из папки. В идеале принцип работы такой, в резолвере прописать логику установки компонентов, в файле конфигурации указать название пакета и его версию, если резолвер такой пакет находит — производим установку, если нет — пропускаем и работаем дальше.
Возможно @Илья Уткин подскажет или поможет с реализацией этой идеи. Это нужно для установки собственных пакетов, которых нет в репозиториях. Свой репозиторий делать ради этого, такая себе идея. Конечно можно установить ручками — но идея как раз избежать этого! :)
Возможно кто-то уже делал такой резолвер и поделится решением.
Так же я интегрировал в свою сборку gulp (для внесения изменений в верстку на лету). Ну это мне просто так удобно, когда верстка рядом с кодом лежит.
В будущем планирую этот билдер выложить в открытый доступ, но сейчас есть 2 небольшие проблемы, вернее одна небольшая, с ней сам справлюсь — а вот вторая большая. Мне нужна помощь в написании ресолвера, который будет устанавливать пакеты из папки. В идеале принцип работы такой, в резолвере прописать логику установки компонентов, в файле конфигурации указать название пакета и его версию, если резолвер такой пакет находит — производим установку, если нет — пропускаем и работаем дальше.
Возможно @Илья Уткин подскажет или поможет с реализацией этой идеи. Это нужно для установки собственных пакетов, которых нет в репозиториях. Свой репозиторий делать ради этого, такая себе идея. Конечно можно установить ручками — но идея как раз избежать этого! :)
Возможно кто-то уже делал такой резолвер и поделится решением.
Вот кусочек кода, думаю, этого хватит, чтобы по примеру написать свой резолвер:
$signature = $packageName . '-' . $data['version'];
$filename = $signature . '.transport.zip';
$file_source = MODX_BASE_PATH . RELATIVE_PATH . 'packages/' . $filename;
if (file_exists($file_source)) {
system('cp -R ' . MODX_BASE_PATH . RELATIVE_PATH . 'packages/' . $filename . ' ' . MODX_CORE_PATH . 'packages/');
$package = $this->modx->getObject('transport.modTransportPackage',array(
'signature' => $signature,
));
if (empty($package)) {
$package = $this->modx->newObject('transport.modTransportPackage');
$package->set('signature', $signature);
$package->set('state', 1);
$package->set('created',strftime('%Y-%m-%d %H:%M:%S'));
$package->set('workspace', 1);
/* set package version data */
$sig = explode('-',$signature);
$package->set('package_name',$sig[0]);
if (!empty($sig[1])) {
$v = explode('.',$sig[1]);
if (isset($v[0])) $package->set('version_major',$v[0]);
if (isset($v[1])) $package->set('version_minor',$v[1]);
if (isset($v[2])) $package->set('version_patch',$v[2]);
}
if (!empty($sig[2])) {
$r = preg_split('/([0-9]+)/',$sig[2],-1,PREG_SPLIT_DELIM_CAPTURE);
if (is_array($r) && !empty($r)) {
$package->set('release',$r[0]);
$package->set('release_index',(isset($r[1]) ? $r[1] : '0'));
} else {
$package->set('release',$sig[2]);
}
}
$package->save();
$package->install();
}
} else {
$this->modx->log('Could not find package file: ' . $filename, 'ERROR');
return false;
}
Спасибо! Насколько я понял, нужно получить signature всех пакетов в указанной папке, signature состоит из (название-версия). Как это можно реализовать?
Ну просто пробегись по списку файлов в папке и составь массив из signature.
Я себе такой скрипт написал, просто запускаешь после установки модх через консоль
Часть с установкой пакетов взял из заметки Василия Наумкина.
Просто в массивах указываете нужные параметры и запускаете.
Не забываем указать логин и пароль администратора в конфигурации.
php modx_config.php
Часть с установкой пакетов взял из заметки Василия Наумкина.
Просто в массивах указываете нужные параметры и запускаете.
Не забываем указать логин и пароль администратора в конфигурации.
<?php
set_time_limit(0);
ini_set('max_execution_time', 0);
// API
require_once 'config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');
$cache = $modx->getCacheManager();
function installPackage($packageName, $provider = 1) {
global $modx;
$provider = $modx->getObject('transport.modTransportProvider', $provider);
$provider->getClient();
$modx->getVersionData();
$productVersion = $modx->version['code_name'].'-'.$modx->version['full_version'];
$response = $provider->request('package','GET',array(
'supports' => $productVersion,
'query' => $packageName
));
if (!empty($response)) {
$foundPackages = simplexml_load_string($response->response);
foreach($foundPackages as $foundPackage) {
/* @var modTransportPackage $foundPackage */
if($foundPackage->name == $packageName) {
$sig = explode('-',$foundPackage->signature);
$versionSignature = explode('.',$sig[1]);
$url = $foundPackage->location;
if (!download($url, $modx->getOption('core_path').'packages/'.$foundPackage->signature.'.transport.zip')) {
return array(
'success' => 0,
'message' => 'Could not download package <b>'.$packageName.'</b>.',
);
}
$package = $modx->newObject('transport.modTransportPackage');
$package->set('signature',$foundPackage->signature);
$package->fromArray(array(
'created' => date('Y-m-d h:i:s'),
'updated' => null,
'state' => 1,
'workspace' => 1,
'provider' => $provider->id,
'source' => $foundPackage->signature.'.transport.zip',
'package_name' => $sig[0],
'version_major' => $versionSignature[0],
'version_minor' => !empty($versionSignature[1]) ? $versionSignature[1] : 0,
'version_patch' => !empty($versionSignature[2]) ? $versionSignature[2] : 0,
));
if (!empty($sig[2])) {
$r = preg_split('/([0-9]+)/',$sig[2],-1,PREG_SPLIT_DELIM_CAPTURE);
if (is_array($r) && !empty($r)) {
$package->set('release',$r[0]);
$package->set('release_index',(isset($r[1]) ? $r[1] : '0'));
} else {
$package->set('release',$sig[2]);
}
}
if ($package->save() && $package->install()) {
return array(
'success' => 1,
'message' => '<b>'.$packageName.'</b> was successfully installed',
);
}
else {
return array(
'success' => 0,
'message' => 'Could not save package <b>'.$packageName.'</b>',
);
}
break;
}
}
}
else {
return array(
'success' => 0,
'message' => 'Could not find <b>'.$packageName.'</b> in MODX repository',
);
}
return true;
}
function download($src, $dst) {
if (ini_get('allow_url_fopen')) {
$file = @file_get_contents($src);
}
else if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $src);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT,180);
$safeMode = @ini_get('safe_mode');
$openBasedir = @ini_get('open_basedir');
if (empty($safeMode) && empty($openBasedir)) {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
}
$file = curl_exec($ch);
curl_close($ch);
}
else {
return false;
}
file_put_contents($dst, $file);
return file_exists($dst);
}
// LOGIN
$_user = [
'username' => 'ваш_логи',
'password' => 'ваш_пароль',
'rememberme' => true,
'login_context' => 'mgr'
];
$response = $modx->runProcessor('/security/login', $_user);
$user = $modx->getObject('modUser', array('username' => $_user['username']));
$modx->user = $user;
print "LOGIN: Done!\n";
// FOLDERS
$_folders = [
'userdata/',
'templates/'
];
foreach ($_folders as $folder) {
$cache->writeTree(MODX_BASE_PATH.$folder);
}
print "FOLDERS: Done!\n";
// RENAME ht.access
rename(MODX_BASE_PATH.'ht.access', MODX_BASE_PATH.'.htaccess');
rename(MODX_BASE_PATH.'core/docs/changelog.txt', MODX_BASE_PATH.'core/docs/_changelog.txt');
print "RENAME: Done!\n";
// MEDIA SOURCES
$_media_sources = [
[
'name' => 'Userdata',
'basePath' => 'userdata/',
'baseUrl' => 'userdata/'
]
];
foreach ($_media_sources as $config) {
$source = $modx->runProcessor('source/create', [
'name' => $config['name'],
'class_key' => 'sources.modFileMediaSource'
]);
if ($source->isError()) {
$modx->log(1, 'Failed to create Source. Message: '.$source->getMessage());
}
$source = $modx->getObject('modMediaSource', $source->response['object']['id']);
$properties = $source->getProperties();
$properties['basePath']['value'] = $config['basePath'];
$properties['baseUrl']['value'] = $config['baseUrl'];
$source->setProperties($properties);
$source->save();
}
print "MEDIA SOURCES: Done!\n";
// PROVIDERS
$_providers = [
[
'name' => 'modstore.pro',
'service_url' => 'https://modstore.pro/extras/',
'username' => '',
'api_key' => '',
'description' => ''
],
];
foreach ($_providers as $properties) {
$provider = $modx->runProcessor('workspace/providers/create', $properties);
if ($provider->isError()) {
$modx->log(1, 'Failed to create Provider. Message: '.$provider->getMessage());
}
}
print "PROVIDERS: Done!\n";
// PACKAGES
$_packages = [
1 => [
'translit',
'FormIt',
'ClientConfig',
'MIGX',
'CKEditor',
'filetranslit',
'Console',
'simpleUpdater',
],
2 => [
'pdoTools',
'Ace',
'phpThumbOn',
'AjaxForm',
]
];
foreach ($_packages as $provider => $packages) {
foreach ($packages as $package) {
installPackage($package, $provider);
print $package.": Done!\n";
}
}
print "PACKAGES: Done!\n";
// RESOURCES
$_resources = [
[
'pagetitle' => '404',
'alias' => '404',
'hidemenu' => 1,
'published' => 1,
'content' => '<p>Такой страницы не существует.</p>'
],
[
'pagetitle' => 'sitemap.xml',
'alias' => 'sitemap',
'content_type' => 2,
'template' => 0,
'hidemenu' => 1,
'published' => 1,
'richtext' => 0,
'content' => '[[!pdoSitemap]]'
],
[
'pagetitle' => 'robots.txt',
'alias' => 'robots',
'content_type' => 3,
'template' => 0,
'hidemenu' => 1,
'published' => 1,
'richtext' => 0,
'content' => "User-agent: *\nDisallow: /"
]
];
foreach ($_resources as $properties) {
$resource = $modx->runProcessor('resource/create', $properties);
if ($resource->isError()) {
$modx->log(1, 'Failed to create Resource. Message: '.$resource->getMessage());
}
}
print "RESOURCES: Done!\n";
// OPTIONS
// get media source id
$default_media_source = $modx->getObject('modMediaSource', [
'name' => $_media_sources[0]['name']
]);
$default_media_source = $default_media_source->toArray()['id'];
// get error page id
$error_page = $modx->getObject('modResource', [
'pagetitle' => $_resources[0]['pagetitle']
]);
$error_page = $error_page->toArray()['id'];
$_options = [
'site_name' => 'SITE_NAME',
'emailsender' => 'ваша_почта',
'server_protocol' => 'http',
'friendly_alias_realtime' => 1,
'friendly_alias_restrict_chars' => 'alphanumeric',
'friendly_alias_translit' => 'russian',
'friendly_urls' => 1,
'friendly_urls_strict' => 1,
'use_alias_path' => 1,
'use_frozen_parent_uris' => 1,
'confirm_navigation' => 0,
'welcome_screen' => 0,
'default_template' => 1,
'link_tag_scheme' => 'abs',
'log_snippet_not_found' => 0,
'log_deprecated' => 0,
'publish_default' => 1,
'feed_modx_news_enabled' => 0,
'feed_modx_security_enabled' => 0,
'send_poweredby_header' => 0,
'ace.font_size' => '14px',
'ace.theme' => 'tomorrow_night',
'pdotools_fenom_options' => '{"strip":true}',
'pdotools_fenom_parser' => 1,
'default_media_source' => $default_media_source,
'error_page' => $error_page
];
foreach ($_options as $key => $value) {
if ($option = $modx->getObject('modSystemSetting', $key)) {
$option->set('value', $value);
$option->save();
}
}
print "OPTIONS: Done!\n";
// CONTENT TYPE
$content_type = $modx->getObject('modContentType', [
'name' => 'HTML'
]);
if ($content_type) {
$content_type->set('file_extensions', '/');
$content_type->save();
}
print "CONTENT TYPE: Done!\n";
// CLEAR CACHE
$cache->refresh();
print "ALL Done!\n";
вот такая ошибка вылетает
Не подскажите в чём дело?
LOGIN: Done!
FOLDERS: Done!
RENAME: Done!
PHP Fatal error: Uncaught Error: Call to a member function getProperties() on null in /home/c/***/public_html/auto_config_site_modx_revo.php:181
Stack trace:
#0 {main}
thrown in /home/c/***/public_html/auto_config_site_modx_revo.php on line 181
это вот эта строка $properties = $source->getProperties();Не подскажите в чём дело?
Видимо Источник файлов не создался по какой-то причине, попробуйте закомментировать этот шаг и эту строку в $_options
'default_media_source' => $default_media_source,
Спасибо за быстрый ответ)
если закомментировать то идёт процесс дальше.
далее на создании ресурсов ломается
если закомментировать то идёт процесс дальше.
далее на создании ресурсов ломается
PACKAGES: Done!
PHP Fatal error: Uncaught Error: Call to a member function get() on null in /home/c/***/public_html/core/model/modx/processors/resource/create.class.php:234
Stack trace:
#0 /home/c/***/public_html/core/model/modx/processors/resource/create.class.php(142): modResourceCreateProcessor->setFieldDefaults()
#1 /home/c/***/public_html/core/model/modx/modprocessor.class.php(641): modResourceCreateProcessor->beforeSet()
#2 /home/c/***/public_html/core/model/modx/modprocessor.class.php(177): modObjectCreateProcessor->process()
#3 /home/c/***/public_html/core/model/modx/modx.class.php(1764): modProcessor->run()
#4 /home/c/***/public_html/test1.php(259): modX->runProcessor('resource/create', Array)
#5 {main}
thrown in /home/c/***/public_html/core/model/modx/processors/resource/create.class.php on line 234
Ресурсы стандартным процессором создаются, там нет ничего необычного. Версия модх какая? На 2.7 работает точно, на других не проверял.
2.7.1
только что поставил
php 7.2
только что поставил
php 7.2
Отличный скрипт в общем был бы, если бы отработал.
не хватает ещё создание шаблонов.
не хватает ещё создание шаблонов.
Все работает, только что проверил на modhost
Возможно вы не указали реквизиты для админки тут
$_user = [
'username' => 'ваш_логи',
'password' => 'ваш_пароль',
'rememberme' => true,
'login_context' => 'mgr'
];
Указал. Я сам создал репозитарий и поставил модуль Console.
Может из за этого глюки были.
С нуля всё получилось. Спасибо Вам.
А не подскажите как внедрить создание шаблонов?
Может из за этого глюки были.
С нуля всё получилось. Спасибо Вам.
А не подскажите как внедрить создание шаблонов?
Можно так, например, перед созданием ресурсов вставить.
Все поля для шаблона можно посмотреть тут в поле fields
// TEMPLATES
$_templates = [
[
'templatename' => 'Название шаблона',
'content' => '<h1>Привет!</h1>'
],
[
'templatename' => 'Еще название шаблона',
'content' => '<h1>Привет еще раз!</h1>'
]
];
foreach ($_templates as $properties) {
$template = $modx->runProcessor('element/template/create', $properties);
if ($template->isError()) {
$modx->log(1, 'Failed to create Resource. Message: '.$template->getMessage());
}
}
print "TEMPLATES: Done!\n";
Все поля для шаблона можно посмотреть тут в поле fields
Спасибо за сборку. Помогает с новыми сайтами. Есть несколько замечаний/предложений:
- Раньше base.tpl подключалось через {include 'file:components/boilerplate/elements/templates/base.tpl'} Почему сейчас поменяли? Теперь при редактировании файла приходится в админку лезть и сбрасывать кеш.
- В базовом шаблоне не хватает h1.
- в шаблоне стоят {'logo' | config} и прочее а самих этих полей не нашел. Может сразу ClientConfig добавить?
- В служебные можно ещё добавить политику конфиденциальности.
- translit почему то не конвертирует alias при создании ресурса на русском.
Спасибо за замечания!
В предыдущем обновлении ошибся, поэтому системные настройки не устанавливались.
ClientConfig добавил в сборку.
В предыдущем обновлении ошибся, поэтому системные настройки не устанавливались.
ClientConfig добавил в сборку.
В базовом шаблоне не хватает h1.Тут уже нужно вставлять самому в чанке или в самом шаблоне.
В служебные можно ещё добавить политику конфиденциальности.Да, добавлю в след. обновлении.
Спасибо. Удобно, работает.
Мой дилетантский комментарий относительно работы компонента.
После обновления компонент вновь перезаписывает шаблон с индексом 1. На рабочем сайте это вообще бывает не удобно. Может лучше новый шаблон создавать?
После обновления компонент вновь перезаписывает шаблон с индексом 1. На рабочем сайте это вообще бывает не удобно. Может лучше новый шаблон создавать?
Отличное замечание. Исправлю
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.