0.00
80 читателей, 69 топиков

Прячем лишнее от менеджеров

Обычно я, когда даю доступ к готовому сайту, то создаю для этого пользователя с ограниченными правами, а пароль администратора даю, если попросят. Каких-то корыстных целей в этом нет, просто со стороны пользователя меньше возможностей что-нибудь поломать.
Несколько дней назад возникла проблема: заказчик потыкал в меню и посчитал оскорбительным, что у него нет прав. И действительно, если в Revo лишнее в меню скрывается от менеджера при настройке прав, то в Evo все видно, хоть и не работает. Решение очень простое:

/* 
Events: OnManagerMenuPrerender, OnManagerPageInit
Configuration:

&role=role;text;2 &hide=hide;textarea;user_management_title,
manager_permissions,
role_management_title,
elements,
reports,
bk_manager,
import_site,
export_site,
edit_settings,
new_module,
web_permissions
*/
$e = $modx->event;
$user = $modx->userLoggedIn();
$data = $modx->getUserInfo($user['id']);
if ($e->name == 'OnManagerMenuPrerender') {
	if ($data['role'] == $role) 
		if(isset($hide))
			foreach(explode(',',$hide) as $item) 
				unset($menu[trim($item)]);
	$e->output(serialize($menu));
}
if ($e->name == 'OnManagerPageInit') {
	if ($data['role'] == $role)
		if(isset($_REQUEST['a']) && $_REQUEST['a'] == 106)
			$modx->sendRedirect(MODX_MANAGER_URL.'index.php?a=2');
}

Плагин прячет для роли Editor лишние пункты меню (названия можно посмотреть в файле manager/frames/mainmenu.php), в том числе модуль Extras, и не дает смотреть страницу «Управление модулями». Портит дело только кнопка «Управление элементами» в дереве, ее нормально не удалить — но там и не пишется, что нет прав, так что пусть остается (:

Мелкие плюшки для админки

Отказавшись от использования плагина ManagerManager стали всплывать некоторые недостающие моменты, которые решились достаточно легко.
Во первых использованием плагина templatesEdit2, а во вторых созданием плагина на событие OnDocFormPrerender.
Ниже речь пойдёт о втором плагине.

Читать дальше →

Ctrl+S в ресурсах

Добрый вечер,
сидел, ковырял сайтик на ево и по привычке (от REVO) после изменений в ресурсах нажимал на CTRL + S и ничего полезного не происходило.

Подумал, погуглил и родился мини плагин на событие OnDocFormRender


Читать дальше →

Поиск дубликатов документов и их удаление

Иногда появляется необходимость в обширных каталогах найти одинаковые документы. При условии что вложенность большая и pagetitle документов не обязательно уникальны.

Моей задачей было удалять старые документы с идентичными ключевыми словами

Источник проблемы:
Сайт с огромным каталогом, импорт объектов из внешнего файла.
Импорт автоматизирован и повешен на крон. При импорте запрашиваются координаты объекта у яндекса, в следствии чего скрипты зависают, а объекты могут продублироваться.

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


<?php
	@ini_set("display_errors","1");
	error_reporting(E_ALL);	

	define('MODX_API_MODE', true);
	include_once(dirname(__FILE__)."/index.php");
	$modx->db->connect();
	if (empty ($modx->config)) {
		$modx->getSettings();
	}

	require_once($basePath.'assets/libs/resourse.php');
	$resourse=resourse::Instance($modx);

	$rsQuery = 'SELECT COUNT(c.id) AS cnt, c.pagetitle, t.value FROM '.$modx->getFullTableName('site_content').' c ';
	$rsQuery.= 'INNER JOIN '.$modx->getFullTableName('site_tmplvar_contentvalues').' t ON t.contentid = c.id AND t.tmplvarid = 3 '; // JOIN уникального ТВ параметра
	$rsQuery.= 'GROUP BY c.pagetitle, t.value HAVING COUNT(c.id) > 1 ORDER BY c.pagetitle';
	$res = $modx->db->query($rsQuery);
	
	if ($res && mysql_num_rows($res) > 0){
		while($i = mysql_fetch_assoc($res)){
			echo("<p>{$i['cnt']} - {$i['pagetitle']} - {$i['value']}</p>");
			$cnt = $i['cnt'] - 1;
			$sres = $modx->db->query("SELECT contentid FROM ".$modx->getFullTableName('site_tmplvar_contentvalues')." WHERE value = '{$i['value']}' ORDER BY contentid ASC LIMIT $cnt");
			if ($sres && mysql_num_rows($sres) > 0){
				while($z = mysql_fetch_assoc($sres)){
					echo("<p>Must-delete = {$z['contentid']}</p>");
					$resourse->delete($z['contentid']);
				}
			}
		}
	}
		
?>


*Код легко расширяется на учёт нескольких ТВ параметров.

Возможно кому-то данный пример будет полезен при решении его задач.

Оптимизация jpg-картинок

Гуглосервис PageSpeed Insights рекомендует «проводить базовую и расширенную оптимизацию всех изображений… При расширенной оптимизации проводится сжатие файлов JPEG и PNG (без потерь).»

Читать дальше →

[EVO] Ошибка при большом обьёме данных в multiTv

Если у кого бывала ситуация когда вы набиваете multiTv данными, и на определённом моменте после сохранения, ресурс больше не открывается — зайдите в phpmyadmin, в таблице modx_site_tmplvar_contentvalues поменяйте тип поля value с TEXT на MEDIUMTEXT.

Как сделать несколько меток со своими изображениями на сайте с помощью Яндекс.Карты API 2.1

Благодаря помощи местных мастеров своего дела решил топик оформить как пример использования API Яндекс карт. В поиске самого Яндекса много информации, но путного нет ничего. Если нужно на карте сделать несколько меток со своим изображением надо делать следующее:

Шаг 1


Подключаем API Яндекса между тэгами ...

<script src="http://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>


Шаг 2


В самом шаблоне сайта, в выводимой области вставляем вывод карты:


<div id="map" style="width: 100%; height: 498px"></div>


Шаг 3


Сам код с метками. Выкладываю на своём примере, надо было по Москве 3 метки гостиниц поставить со своим дизайном:


<script type="text/javascript">
ymaps.ready(init);

function init () {

var myMap = new ymaps.Map("map", {
                center: [55.6938,37.6001],
                zoom: 11,
				controls: ['zoomControl']
            }); 


var myGeoObjects = [];
        
        myGeoObjects[0] = new ymaps.Placemark([55.6740,37.7333],{
				clusterCaption: 'Заголовок', 
			//balloonContentBody: 'Текст в балуне',
				},{
				// Необходимо указать данный тип макета.
				iconLayout: 'default#image',
				iconImageHref: 'images/pointer_3.png',
				// Размеры метки.
				iconImageSize: [151, 41],
				// Смещение левого верхнего угла иконки относительно
				// её «ножки» (точки привязки).
				iconImageOffset: [-3, -42]
				});
        
        myGeoObjects[1] = new ymaps.Placemark([55.6990,37.7377],{
				clusterCaption: 'Заголовок', 
			//balloonContentBody: 'Текст в балуне',
				},{
				// Необходимо указать данный тип макета.
				iconLayout: 'default#image',
				iconImageHref: 'images/pointer_2.png',
				// Размеры метки.
				iconImageSize: [176, 52],
				// Смещение левого верхнего угла иконки относительно
				// её «ножки» (точки привязки).
				iconImageOffset: [-23, -42]
		});
	
        myGeoObjects[2] = new ymaps.Placemark([55.7377,37.6501],{
				clusterCaption: 'Заголовок', 
			//balloonContentBody: 'Текст в балуне',
				},{
				// Необходимо указать данный тип макета.
				iconLayout: 'default#image',
				iconImageHref: 'images/pointer_1.png',
				// Размеры метки.
				iconImageSize: [165, 40],
				// Смещение левого верхнего угла иконки относительно
				// её «ножки» (точки привязки).
				iconImageOffset: [-16, -42]
		});
        
var clusterIcons=[{
        href:'/images/pointer.png',
        size:[31,40],
        offset:[0,0]
}];
        
   var clusterer = new ymaps.Clusterer({
        clusterDisableClickZoom: false,
        clusterOpenBalloonOnClick: false,
        // Устанавливаем стандартный макет балуна кластера "Карусель".
        clusterBalloonContentLayout: 'cluster#balloonCarousel',
        // Устанавливаем собственный макет.
           //clusterBalloonItemContentLayout: customItemContentLayout,
        // Устанавливаем режим открытия балуна. 
        // В данном примере балун никогда не будет открываться в режиме панели.
        clusterBalloonPanelMaxMapArea: 0,
        // Устанавливаем размеры макета контента балуна (в пикселях).
        clusterBalloonContentLayoutWidth: 300,
        clusterBalloonContentLayoutHeight: 200,
        // Устанавливаем максимальное количество элементов в нижней панели на одной странице
        clusterBalloonPagerSize: 5
        // Настройка внешего вида нижней панели.
        // Режим marker рекомендуется использовать с небольшим количеством элементов.
        // clusterBalloonPagerType: 'marker',
        // Можно отключить зацикливание списка при навигации при помощи боковых стрелок.
        // clusterBalloonCycling: false,
        // Можно отключить отображение меню навигации.
        // clusterBalloonPagerVisible: false
    });

clusterer.add(myGeoObjects);
myMap.geoObjects.add(clusterer);
}
</script>


Пример карты можно посмотреть тут www.project-i.ru/contacts.html

Нашёл пару полезных линков:
api.yandex.ru/maps/tools/getlonglat/ — криво определяет
u-karty.ru/opredelenie-koordinat-na-karte-yandex — адекватный поиск
api.yandex.ru/maps/jsbox/2.1/placemark

Огромное спасибо за наставления 118RUS и webber

Ajax. Метод №3

Вкратце о раннее рассказанных методах.
1) Отправляем ajax запрос на туже страницу где мы находимся, а с ответа в нужном html теге вырезаем результат
+ простота
— скорость
— необходимость вырезать из ответа нужное
2) Через index-ajax.php Урок или на прямую на php файл
+ скорость
— необходимость подготовки скриптов их прописыванию
— правка кода через фтп
— необходимо иметь заготовку
3) Тут подробнее. Данный метод у некоторых людей поменяет стиль программирования в МОДх ))))

— создайте плагин AJAX с кодом

switch($_GET['q']){	
	case 'liked':
	    echo $_POST['value'].'-OK';  //вот тут код отработки вашего кода
            // выведим просто значение $_POST['value'] 
	break;
}
die();


— выставите его на событие OnPageNotFound

Все. Заготовка готова. Такой код запоминается на раз-два-три.
Самое интересное как этим пользоваться. Еще не догадались???? ))))

в консоли firebug давайте потестим как оно работает


$.ajax({
    url:'liked',
    type:'post',
    data:{
        value:1
    }
})


Ответом сервера будет «1-ОК» )) Все работает…

Для тех кому интересен принцип:
— идёт запрос на сервер по URL: liked
— так как его не существует (здесь вся соль) выполняется событие OnPageNotFound
— наш плагин как раз на данном событии
— .htaccess MODx преобразует frienly url в переменную которую отсылает GET параметром на index.php — потому используем $_GET['q'] для определения action

И что мы емеем. Для разных action мы просто прописуем их в case '':. на эти url шлем запросы.

+ скорость
+ простота (может и не с первого раза, но гарантирую что вы подсядите)