Инструменты пользователя

Инструменты сайта


simple_integration

Быстрый старт - Внедрение Shopkeeper на простом примере

В этой статье рассмотрен процесс создания очень простого магазина шаг за шагом. Это позволит познакомиться с основными принципами работы Shopkeeper и может послужить отправной точкой для более сложных проектов.

Внимание! Это статья для новичков в Shopkeeper, но не для новичков в MODX.
Предполагается, что вы знакомы с базовыми понятиями MODX и знаете, что такое чанк, сниппет, ресурс, шаблон, переменная шаблона (TV), плейсхолдер, знаете хотя бы основы синтаксиса MODX и не пугаетесь, увидев в коде что-то типа [[$chunk]] или [[!snippet]]. Если нет — пожалуйста, сначала ознакомьтесь с основными понятиями MODX (например, здесь — http://develop.modx.com/develop/revolution/quickstart/, или здесь - http://modx.ws/). Не имея хотя бы самых базовых знаний, вам будет тяжело понять дальнейшие инструкции. Если у вас нет никакого опыта создания сайтов на MODX, не стоит начинать с такого сложного проекта, как интернет-магазин.
Также предполагается, что у вас есть хотя бы самые базовые знания html и css.

Типичный интернет-магазин включает в себя:

  • каталог товаров
  • страницу с детальным описанием товара
  • корзину покупок (и возможность добавлять товары в нее)
  • форму заказа, позволяющую оплатить выбранные товары, указать адрес доставки, способ оплаты и т. д.

Как реализовать это с помощью Shopkeeper?

Создание каталога товаров

Создать несложный каталог можно даже до того, как Shopkeeper установлен, пользуясь только стандартным функционалом MODX. Товары — это просто ресурсы MODX, которым с помощью TV назначены дополнительные свойства. Как минимум, у товара должна быть цена, также у него могут быть размеры, вес, цвета, изображения, варианты — все зависит от того, что именно будет продаваться в интернет-магазине.

  1. Cначала создайте ресурсы, которые будут выступать в качестве категорий товаров;
  2. внутри каждой категории создайте ресурсы, которые будут являться собственно товарами;
  3. создайте новую переменную шаблона (TV) типа «число», в которой будет храниться цена товара, и назначьте ее шаблону товара. По умолчанию Shopkeeper считает, что TV с ценой называется «price», поэтому лучше так ее и назвать. Название может быть и другим, но для простоты предположим, что TV имеет стандартное имя.
  4. Как правило, у товаров в интернет-магазине есть хотя бы одно изображение, поэтому есть смысл добавить также TV с типом «изображение» и назначить ее шаблону товара (имя на этот раз может быть любым. Давайте назовем эту TV «image»). Хотя каждому товару можно назначать неограниченное число изображений (например, с помощью дополнения MIGX), для этого урока ограничимся одной картинкой.






Пример простейшего шаблона для товара

<html>
    <head>
        <title>[[*pagetitle]]</title>
    </head>
    
    <body>
        <h1>[[*pagetitle]]</h1>
        [[*content]]
        <p>Цена: [[*price]]</p>
    </body>
</html>

Вывод списка товаров категории с помощью сниппета getResources

Поскольку товары в нашем магазине - ни что иное, как обычные ресурсы MODX, мы можем вывести список товаров в категории с помощью всем известного сниппета getResources

Простейший шаблон вывода списка товаров категории может выглядеть так:

<html>
    <head>
        <title>[[*pagetitle]]</title>
    </head>
    
    <body>
        [[getResources?
            &tpl=`categoryItem`
            &includeTVs=`1`
            &processTVs=`1`
	    &limit=`0`
        ]]
    </body>
</html>

Ресурс с таким шаблоном будет выводить все дочерние ресурсы, отформатированные в соответствии с чанком «categoryItem», который мы должны предварительно создать и который может выглядеть вот так:

<div class="product">
    <a href="[[~[[+id]]]]">[[+pagetitle]]</a>
    [[+tv.image]]
    Цена: [[+tv.price]]
</div>

getProducts - более быстрая альтернатива getResources

getResources - очень мощный сниппет, но это инструмент общего назначения. Для работы с каталогом есть специализированный сниппет getProducts, оптимизированный для большей скорости. Его параметры очень похожи на параметры getResources и во многих случаях его можно безболезненно заменить. Например, в шаблоне категории вызов

    [[getResources?
        &tpl=`categoryItem`
        &includeTVs=`1`
        &processTVs=`1`
        &limit=`0`
    ]]

можно заменить на

    [[getProducts?
        &tpl=`categoryItem`
        &includeTVs=`1`
        &processTVs=`1`
        &limit=`0`
    ]]

Конечно, можно пользоваться и обычным getResources, но на больших каталогах разница в скорости будет заметна.

Сниппет getProducts не идет в комплекте с основным пакетом Shopkeeper, но написан тем же автором и бесплатно устанавливается из репозитория modx.com. Также его можно скачать и установить вручную из каталога дополнений MODX - http://modx.com/extras/package/getproducts

Установка и первоначальная настройка Shopkeeper

До сих пор мы работали со стандартным функционалом MODX, и создали простой каталог товаров. Теперь надо превратить наш каталог в интернет-магазин. На этот раз стандартными средствами не обойтись, и мы приступаем к установке и настройке Shopkeeper. Он устанавливается точно также, как и любое другое дополнение:

  • Можно скачать дополнение в административной части сайта. Для этого перейти в «Система» → «Управление пакетами». Нажать кнопку «Скачать дополнение». Далее перейти «Extras» → «E-commerce» и в строке «Shopkeeper» нажать кнопку «Загрузить», потом кнопку «Готово».
    Если вы скачали файл с сайта modx.com, загрузите архив «shopkeeper-2.x-x.transport.zip» в папку core/packages/ вашего сайта, затем в панели управления перейдите в раздел «Система» → «Управление пакетами», нажмите «Добавить новый пакет» → «Искать пакеты локально» → «Дальше».
  • В таблице пакетов появится пакет «shopkeeper». Нажать кнопку «Установить».
  • Закончить установку.

Shopkeeper установлен, и теперь мы можем выводить на страницах нашего магазина корзину покупок. Для этого надо просто добавить в шаблоны вызов одноименного сниппета: [[Shopkeeper]]. На сайте на месте вызова этого сниппета появится корзина с набором настроек по умолчанию.

Кроме того, в верхнем меню менеджера, в разделе «Компоненты», добавится пункт «Управление заказами».

Первоначальная настройка

Чтобы выполнить настройку компонента, нужно в дереве элементов открыть вкладку «Сниппеты», в ней - Shopkeeper, открыть одноименный сниппет и перейти на вкладку «Параметры».

Настроек много, полная документация по ним здесь и здесь. Мы пройдемся по самым основным.

  • prodCont - CSS-селектор элемента, внутри которого находится информация о товаре (по умолчанию `div.shk-item`). Это поле нужно для того, чтобы Shopkeeper «знал», какие из множества элементов на странице являются описаниями товаров и что можно добавлять в корзину. Если это поле заполнено неправильно, товар в корзину добавляться не будет.
  • cartTpl - Шаблон корзины (по умолчанию `@FILE shopCart.tpl`). По умолчанию Shopkeeper хранит все свои чанки во внешних файлах, которые лежат в каталоге core/components/shopkeeper/elements/chunks/<язык>/. Файл shopCart.tpl отвечает за внешний вид и содержимое корзины. Чтобы изменить корзину, нужно либо отредактировать этот файл (который представляет собой обычный html-код с MODX-тегами), либо создать для корзины новый чанк и указать его имя в качестве значения cartTpl.
  • cartRowTpl, additDataTpl, orderDataTpl, cartHelperTpl - дополнительные шаблоны, которые отвечают за вид и содержимое различный частей корзины. Также лежат во внешних файлах.
  • priceTV - имя переменной шаблона, в которой хранится цена товара. По умолчанию «price».
  • currency - валюта. Это не обязательно должен быть международный код валюты типа EUR, RUR, USD, это может быть произвольная строчка, например «руб», «р.» или «&euro;»
  • orderFormPage - ID ресурса, на котором размещена форма заказа. Если оставить это поле пустым, кнопка «Оформить заказ» в корзине не появится.
  • noJQuery - не подгружать библиотеку jQuery, по умолчанию - «0». По умолчанию Shopkeeper загружает свою версию jQuery. На очень многих сайтах jQuery уже установлена, и дублирование часто является причиной проблем. Если на вашем сайте уже есть jQuery, присвойте этому полю значение «1».

Наборы параметров

Как вы уже поняли из предыдущего пункта, основной компонент Shopkeeper'а - одноименный сниппет, т.е. кусок php-кода. Сниппеты в MODX могут вызываться с различными параметрами. Если считать сниппет функцией, то передаваемые параметры - это аргументы функции. Например, вывести корзину с отключенной jQuery можно так:

[[Shopkeeper? &nojQuery=`1`]]

Вывести корзину без jQuery и с нестандартным шаблоном можно так:

[[Shopkeeper? &nojQuery=`1` &cartRowTpl=`myCustomCart` ]]

Если мы хотим переопределить большое количество параметров, то вызов сниппета становится раздутым и неудобным:

[[Shopkeeper? &noJavaScript=`1` &cartRowTpl=`myCustomCart` &currency='RUR' &noCounter=`1` &orderFormPage=`10` &goToOrderFormPage=`1` &allowFloatCount=`1` &animCart=`0` ]]

Вместо того, чтобы передавать в сниппет каждый параметр по отдельности, проще и удобнее сделать для корзины отдельный набор параметров (или несколько), и вызывать сниппет, указывая этот набор, например, так:

[[!Shopkeeper@cart_catalog?propertySetName=`cart_catalog`]]

Эта запись намного лаконичнее и удобнее в использовании.

Внимание! Если вы используете AJAX-корзину (а это, скорее всего, так), параметры должны обязательно передаваться сниппету именно в виде набора, а не по отдельности. Использование сниппета без набора параметров возможно только в случае, если корзина используется без Javascript (параметр noJavaScript=`1`).

Не стоит изменять значения в наборе параметров по умолчанию, потому что при обновлении сниппета эти настройки могут потеряться. Лучше сделать отдельные наборы параметров и вызывать сниппет с ними.

Подробнее о наборах параметров и их использовании - http://rtfm.modx.com/revolution/2.x/making-sites-with-modx/customizing-content/properties-and-property-sets
Если раньше вы не работали с наборами параметров - не пожалейте времени на изучение, это очень просто и сильно облегчает жизнь в разработке на MODX.

Несколько корзин на сайте

Часто в интернет - магазинах есть несколько корзин. Например, маленькая корзинка в хедере сайта, показывающая минимум информации, и подробная корзина с формой заказа на отдельной странице.

Подробная корзина со списком товаров

Обе корзины вызываются одним и тем же сниппетом [[Shopkeeper]] , но с разными наборами параметров.

Внимание! На странице может быть только один вызов Shopkeeper! Если сниппет вызывается больше одного раза, то обрабатывается только первый вызов, остальные - игнорируются!

Множественный вызов сниппета является частой ошибкой. Типичным сценарием является двойной вызов на странице подробной корзины, когда Shopkeeper вызывается и в шапке сайта, и в теле документа. Чтобы показать подробную корзину, нам нужно запретить вызов сниппета в шапке. Для этого нужно в наборе параметров маленькой корзины заполнить свойство hideOn, указав один или несколько ID страниц, где маленькую корзину вызывать не нужно. Как правило, достаточно вписать сюда только ID страницы, где размещена подробная корзина.

Добавление кнопки "Купить"

Итак, в нашем магазине есть каталог товаров и корзина покупок, но положить товар в корзину мы пока не можем. Чтобы сделать это, нам нужно добавить кнопку «Купить» (или «Добавить в корзину») на страницы категории и подробного описания товара.

Добавление кнопки корзины к подробному описанию товара

Начнем с того, что добавим кнопку корзины на страницу подробного описания товара. Пример кода для этой кнопки лежит в файле /core/components/shopkeeper/elements/chunks/<язык>/shopToCart.tpl

<div class="product-tocart shk-item">
<form action="[[~[[*id]]? &scheme=`abs`]]" method="post">
  <input type="hidden" name="shk-id" value="[[*id]]" />
  <input type="hidden" name="shk-name" value="[[*pagetitle]]" />
  <input type="hidden" name="shk-count" value="1" />
  <div align="right">
    Цена: <span class="shk-price" id="stuff_[[*id]]_price">[[*price]]</span> руб.
    <button type="submit" name="shk-submit" class="shk-but">В корзину</button>
  </div>
</form>
</div>

Давайте вставим этот код в шаблон страницы товара, который мы сделали ранее:

<html>
    <head>
        <title>[[*pagetitle]]</title>
    </head>
    
    <body>
        <h1>[[*pagetitle]]</h1>
        [[*content]]
        <div class="product-tocart shk-item">  <!-- код кнопки КУПИТЬ -->
            <form action="[[~[[*id]]? &scheme=`abs`]]" method="post"> 
                <input type="hidden" name="shk-id" value="[[*id]]" />
                <input type="hidden" name="shk-name" value="[[*pagetitle]]" />
                <input type="hidden" name="shk-count" value="1" />
                    <div align="right">
                    Цена: <span class="shk-price" id="stuff_[[*id]]_price">[[*price]]</span> руб.
                    <button type="submit" name="shk-submit" class="shk-but">В корзину</button>
                </div>
            </form>
        </div>  <!-- /код кнопки КУПИТЬ -->
    </body>
</html>

После этого на странице с описанием товара появится кнопка «В корзину», и по нажатию на нее товар начнет добавляться в корзину.

Внимание! Обратите внимание, что div, содержащий в себе кнопку добавления товара, имеет класс .shk-item. Ранее мы упоминали, что у снипппета Shopkeeper есть параметр prodCont, который имеет значение по умолчанию div.shk-item. Если вы измените этот класс в своей верстке, не забудьте изменить и значение prodCont в настройках Shopkeeper. Если этого не сделать, товары в корзину добавляться не будут, или будут добавляться некорректно! Это малоочевидный момент, о котором надо помнить, меняя верстку, идущую по умолчанию.

Добавление кнопки корзины на страницу категории товара

Чтобы добавить кнопку «Купить» в шаблон категории товара, приведенный выше код надо немного модифицировать. Поскольку мы выводим список товаров с помощью сниппета getProducts (или getResources), вывод полей документа нужно заменить на вывод соответствующих плейсходлеров. Вот как выглядит чанк categoryItem после модификации:

<div class="product">
    <a href="[[~[[+id]]]]">[[+pagetitle]]</a>
    [[+tv.image]]
    <form action="[[~[[*id]]? &scheme=`abs`]]" method="post">
        <fieldset>
            <input type="hidden" name="shk-id" value="[[+id]]" />
            <input type="hidden" name="shk-name" value="[[+pagetitle]]" />
            <input type="hidden" name="shk-count" value="1" />
            <div class="product-price">
                <button type="submit" class="shk-but">В корзину</button>
                <div>Цена: <span class="shk-price">[[+tv.price:num_format]]</span> руб.</div>
            </div>
        </fieldset>
    </form>
</div>

Обратите внимание, что вызовы полей ресурса типа [[*pagetitle]] мы заменили на вызов плейсхолдеров [[+pagetitle]], а к вызову TV (цена и изображение товара) добавили соответствующий префикс.

Рабочий пример вывода товара в каталоге лежит в файлах /core/components/shopkeeper/elements/chunks/<язык>.product1.tpl и product2.tpl

Создание формы оформления заказа

Чтобы покупатели могли оформить покупку товаров, которые они добавили в корзину, на сайте должна быть форма заказа. Простым и очевидным решением будет разместить ее на странице с «большой» корзиной.

При установке Shopkeeper в список чанков добавляется чанк ShopOrderForm. Все, что нам нужно - вывести его на странице оформления заказа (она же - страница подробной корзины в нашем случае), и обработать эту форму сниппетом FormIt.

Вот как это может выглядеть:

[[!Shopkeeper@cart_order_page?propertySetName=`cart_order_page`]]
   
[[!FormIt?
&hooks=`spam,shk_fihook,email,FormItAutoResponder,redirect`
&submitVar=`order`
&emailTpl=`shopOrderReport`
&fiarTpl=`shopOrderReport`
&emailSubject=`В интернет-магазине "[[++site_name]]" сделан новый заказ`
&fiarSubject=`Вы сделали заказ в интернет-магазине "[[++site_name]]"`
&emailTo=`[[++emailsender]]`
&redirectTo=`13`
&validate=`address:required,fullname:required,email:email:required,phone:required`
&errTpl=`<br /><span class="error">[[+error]]`
]]
   
[[!$shopOrderForm]]

Этот код можно логически разделить на три части:

здесь мы выводим корзину со списком товаров:

[[!Shopkeeper@cart_order_page?propertySetName=`cart_order_page`]]

выводим чанк с формой заказа:

[[!$shopOrderForm]]

…и вызываем сниппет FormIt, который будет эту форму обрабатывать:

[[!FormIt?
&hooks=`spam,shk_fihook,email,FormItAutoResponder,redirect`
&submitVar=`order`
&emailTpl=`shopOrderReport`
&fiarTpl=`shopOrderReport`
&emailSubject=`В интернет-магазине "[[++site_name]]" сделан новый заказ`
&fiarSubject=`Вы сделали заказ в интернет-магазине "[[++site_name]]"`
&emailTo=`[[++emailsender]]`
&redirectTo=`13`
&validate=`address:required,fullname:required,email:email:required,phone:required`
&errTpl=`<br /><span class="error">[[+error]]`
]]

В этой статье мы не будем подробно останавливаться на описании работы FormIt, если вы не знаете, как он работает - пожалуйста, ознакомьтесь с документацией по этому сниппету. Вкратце, он просто собирает данные нашей формы и по очереди выполняет сниппеты, указанные в параметре &hooks. В данном примере FormIt:

  • проверяет форму на предмет спама
  • сохраняет заказ покупателя в компонент «Управление заказами»
  • отправляет email администратору магазина о новом заказе
  • отправляет email покупателю с подробностями его заказа
  • перенаправляет покупателя на страницу, ID которой указан в параметре redirectTo

После того, как заказ сделан, он добавляется в компонент «Управление заказами», который доступен в админке сайте из верхнего меню, на вкладке «Компоненты»

Подключение платежных систем

До сих пор все примеры из этой статьи можно было применять непосредственно. К сожалению, все платежные системы подключаются по-разному, поэтому дать готовый рецепт невозможно. Мы рассмотрим минимальный пример подключения некой идеализированной платежной системы, это поможет понять принцип работы и подключать настоящие ПС самостоятельно.

Если описанное ниже покажется вам слишком сложным, вы можете приобрести дополнение Paykeeper, которое берет на себя большую часть работы. Хотя дополнение платное, цена его - чисто символическая.

Подключение каждой платежной системы индивидуально, но все они работают примерно по одному принципу:

  1. мы должны отправить платежной системе информацию о заказе (как минимум сумму заказа), и свою идентификационную информацию, чтобы ПС знала, какой интернет-магазин будет получателем платежа,
  2. платежная система проводит платеж (на сайте нашего магазина или на своем сайте), после чего возвращает нам ответ,
  3. мы смотрим на ответ и если ПС сообщила, что платеж прошел успешно, мы должны изменить статус заказа на «оплачен» и отправить клиенту товар, предоставить ссылку для скачивания и тд,
  4. если ПС сообщает об ошибке, мы должны обработать это сообщение и среагировать на него.

Каждая платежная система работает по-разному, но в общих чертах процесс выглядит именно так.

Отправка платежной системе информации о заказе

Есть несколько способов отправки информации с одного сайта на другой. Основные способы это:

  • Отправка с помощью html-формы;
  • Отправка из скрипта с помощью нативного php (в случае MODX - из сниппета или плагина);
  • Отправка из скрипта с помощью внешних программ, например cURL.

Сами данные также передаются в различных форматах - NVP, XML, JSON и т.д. Чтобы узнать, в каком формате и каким способом обменивается данными ваша платежная система, читайте документацию по ее API.

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

Отправка с помощью html-формы

Пример простейшей формы, которая передает на сайт http://payment-operator.com три значения - ID магазина, сумму платежа и адрес, по которому мы хотим получить ответ платежной системы:

<form action="http://payment-operator.com">
    <input type="hidden" name="ID" value="123456">
    <input type="hidden" name="returnUrl" value="http://mysite.com/return.html">
    <input type="text" name="totalcount" value="200">
    <input type="submit" value="Отправить">
</form>

При нажатии на кнопку «Отправить» мы перейдем на страницу http://payment-operator.com, и туда же передадим данные формы в формате NVP(name-value par, пара «имя»-«значение»).

Некоторые платежные системы предоставляют готовые формы, которые просто нужно добавить на свой сайт. В нашем примере для этого нужно сделать страницу «Подтверждение платежа», вставить туда платежную форму в соответствии с инструкцией платежной системы и перенаправлять пользователя на эту страницу, когда он в корзине нажимает кнопку «Оплатить». Поскольку корзина по сути сама является формой и обрабатывается сниппетом FormIt, это можно сделать с помощью хука redirect (подробнее о том, что это такое и как работает - в официальной документации).

В примере корзины, который приведен в разделе «Создание формы оформления заказа», редирект уже настроен и перенаправляет пользователя на страницу с ID 13.

Отправка данных с помощью сниппета или плагина

Использование форм не всегда удобно и не оптимально с точки зрения безопасности.

В предыдущем пункте для того, чтобы отправить заказ платежной системе, нам пришлось ввести дополнительный шаг «подтверждение заказа». Этого можно избежать, если отправлять данные с помощью php. Кроме того, посмотрев исходный код страницы, любой человек может узнать наш ID в платежной системе, что обычно крайне нежелательно.

Давайте создадим новы сниппет sendPaymentData, содержащий такой код:

<?php
$data = array(
    'ID' => '123456',
    'totalcount' => '200'
    'returnUrl' => 'http://mysite.com/return.html'
);

$modx->sendRedirect("http://payment-operator.com?ID={$data['ID']}&totalcount={$data['totalcount']}&returnUrl={$data['returnUrl']}");

Этот сниппет делает то же, что и форма - перенаправляет нас на сайт платежной системы и передает туда же необходимые данные. Плюсом является то, что для этого нам не нужно вводить дополнительный шаг для оплаты заказа, достаточно просто вписать имя нашего сниппета в список хуков FormIt на странице корзины покупок. Например, так:

[[!FormIt?
&hooks=`spam,shk_fihook,email,FormItAutoResponder,sendPaymentData` // !!!
&submitVar=`order`
&emailTpl=`shopOrderReport`
&fiarTpl=`shopOrderReport`
&emailSubject=`В интернет-магазине "[[++site_name]]" сделан новый заказ`
&fiarSubject=`Вы сделали заказ в интернет-магазине "[[++site_name]]"`
&emailTo=`[[++emailsender]]`
&validate=`address:required,fullname:required,email:email:required,phone:required`
&errTpl=`<br /><span class="error">[[+error]]`
]]

Обратите внимание, что в список хуков мы добавили имя нашего нового сниппета и убрали хук redirect, поскольку теперь мы делаем редирект в самом сниппете.

Вместо сниппета мы можем использовать плагин. Плагин - это также всего лишь кусок php-кода, который в отличие от сниппета вызывается не вручную, а как реакция на событие. Чтобы отправлять информацию с помощью плагина, нужно:

  1. создать плагин с тем же кодом, что и у сниппета
  2. привязать его к событию OnSHKsaveOrder

Подробнее о плагинах MODX - в официальной документации.

Список событий Shopkeeper-а - на соответствующей странице вики.

В этой статье мы будем считать, что используется не плагин, а именно сниппет.

simple_integration.txt · Последние изменения: 2016/04/23 15:44 (внешнее изменение)