Как составить шаблон для текста

Многие из нас пользовались шаблонизаторами текстов. Twig в PHP, text/template в Go, Jinja в Python — их сотни.

Но задумывались ли вы, как они устроены внутри? Какие вообще есть способы исполнить шаблон со сложными конструкциями? В этой статье разбираются возможные оптимизации и проблемы, которые могут возникнуть в той или иной реализации, а также то, как на наши решения может влиять язык программирования, на котором мы создаём этот шаблонизатор.

Наиболее детально рассмотрим KTemplate, который я написал для KPHP (на PHP он тоже работает без проблем).

Какие бывают языки шаблонов

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

Обычно мы ожидаем, что в среднестатистическом шаблонизаторе будут следующие возможности:

  • циклы (for) и базовые условные конструкции (if);
  • вставка динамических данных в произвольную часть шаблона;
  • базовые функции для преобразования данных, типа trim;
  • механизмы экранирования;
  • подключение одних шаблонов в другие (наследование или include);
  • расширяемость хотя бы на уровне определения своих функций.

Больше всего мне знакомы шаблонизаторы, применяемые в server-side рендеринге. Эти шаблоны состоят из конструкций следующих категорий:

  1. Текст вне выражений. Никак не преобразуется (но на него могут влиять другие теги).
  2. Выражения, результат вычисления которых подставляется вместо самого выражения.
  3. Особые конструкции, типа if. Результат рендеринга зависит от конкретного оператора.

Выражения выделяются особыми токенами. Это может быть, например, пара {{ и }}. Особые операторы могут иметь как такой же синтаксис, так и слегка отличный (например, {% и %}).

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

{% if item %}
    <p>{{ item.name }}:</p>
{% end %}

Если посмотреть на этот шаблон с точки зрения шаблонизатора, то получим следующее:

IfStatement
    cond={
        Lookup key="item"
    }
    body={
        EchoText value="n  <p>"
        EchoExpr expr={
            Lookup key="item.name"
        }
        EchoText value=":</p>n"
    }

Это видение поможет нам далее, когда мы будем размышлять о том, как это всё можно вычислять.

Способы компиляции и исполнения шаблона

Для начала нам нужно ответить на вопрос, где могут применяться шаблоны.

  • В client-side и server-side рендеринге интерфейсов (не ограничено вебом).
  • В преобразовании данных или генерации новых.
  • В кодогенерации (это не всегда самый аккуратный вариант, зато простой).
  • В параметре для форматирования результатов (например, go list -f).

Несколько примеров того, что имеется в виду под go list:

# Шаблоны в Go немного причудливые...

$ go list -f '{{len .Deps}}' errors
14

$ go list -f '{{join .Imports "n"}}' errors
internal/reflectlite

$ go list -f '{{range .GoFiles}}{{printf "> %sn" .}}{{end}}' errors
> errors.go
> wrap.go

Шаблоны могут быть динамическими или статическими. Статическими мы можем назвать те шаблоны, которые никогда не меняются и известны на этапе запуска (или компиляции) проекта. Динамические шаблоны могут генерироваться на лету или задаваться пользователями.

Динамические шаблоны могут быть полезны для систем, которые позволяют сконфигурировать приложение без его перекомпиляции. Они также нужны в примере с go list -f. Утилита phpgrep тоже использует text/template для форматирования результатов.

Основные способы преобразовать исходный код в готовый к исполнению вид:

  1. Сгенерировать код на некотором ЯП*, который реализует конкретный шаблон.
  2. Исполнить шаблон в текущем контексте, без подгрузки нового кода.

Чаще всего «некоторый язык программирования» — это тот же язык программирования, но для приложения на C мы можем представить использование Lua для шаблонизации.

После такого преобразования (компиляции шаблона) мы можем его исполнить сколько угодно раз.

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

Для программ, которые будут исполняться через интерпретатор, кодогенерация и последующая загрузка сгенерированных исходников — это один из самых популярных и эффективных способов реализовать шаблонизацию. Twig работает именно так.

Для программ на KPHP эта опция недоступна. Если при этом нужна поддержка динамических шаблонов, то придётся выбирать второй вариант и исполнять эти шаблоны своими силами. text/template из Go тоже работает по этому принципу, а вот valyala/quicktemplate генерирует Go-код перед его запуском (первый способ, шаблоны статические).

И в первом, и во втором случае нам придётся распарсить исходный текст шаблона. Отличаться будет то, что мы будем с этим деревом разбора делать дальше.

KTemplate почти во всём копирует синтаксис Twig. Пока будем считать все различия незначительными, но вернёмся к ним ближе к концу статьи.

Исполнение через кодогенерацию

valyala/quicktemplate компилирует шаблоны в Go-файлы, которые затем нужно включать в сборку приложения. Обновление таких шаблонов во время исполнения в теории возможно, но на практике этим лучше не заниматься.

Работают такие шаблоны очень быстро. С точки зрения Go, во время исполнения никаких шаблонов не существует (по крайней мере, их не нужно парсить и компилировать). По особому ключу мы вызываем нужную функцию, а она выполняет ряд операций для создания результата рендеринга.

Шаблон из нашего примера выше может превратиться во что-то такое:

// {% if item %}
//     <p>{{ item.name }}:</p>
// {% end %}
func renderExample(w *writer, data any) {
    if toBool(getItem(data, "item")) {
        w.WriteString("n  <p>")
        w.WriteAny(getItem(data, "item", "name"))
        w.WriteString(":</p>n")
    }
}

Twig и многие другие шаблонизаторы работают по такому же алгоритму, но код может генерироваться и загружаться прямо во время работы приложения. В PHP можно без проблем создать файл с классом, а потом подключить его через autoloader или прямой require.

Когда мы запускаем скомпилированный Twig-шаблон, он всё равно будет интерпретироваться, но не нашей программой (на PHP), а самим интерпретатором PHP (на C).

Исполнение через прямое интерпретирование

text/template и html/template строят из текста шаблона что-то вроде AST с дополнительной информацией для исполнения.

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

Минусы такого подхода:

  • нетривиальная сериализация;
  • шаблоны, готовые к исполнению, занимают избыточное место в памяти;
  • относительно низкая скорость исполнения шаблонов.

Преимущества — простота реализации и скорость компиляции шаблонов.

Кстати, один из интерпретаторов Go, написанный на Go, yaegi, тоже использует обход деревьев для исполнения. Это одна из причин, почему его производительность оставляет желать лучшего.

KTemplate идёт дальше. Дерево разбора преобразуется во что-то вроде байт-кода для последующего исполнения (сам AST нам после этого не нужен).

Преимущества байт-кода почти противоположны минусам обхода дерева:

  • Простая сериализация. Просто набор байтов, который мы пишем и читаем как есть
  • Байт-код гораздо компактнее, чем развесистые деревья
  • Неплохая скорость исполнения шаблонов

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

Байт-код можно превращать в нативный через JIT-компиляцию. Поскольку система команд шаблонизаторов обычно довольно простая, компилировать их в нативный код на лету — задача выполнимая. Тем не менее здесь могут быть нюансы. Например, в том же Go реализовать JIT-компиляцию довольно трудно. Если генерировать машинный код сразу, без байт-кода, то многие проблемы исполнения останутся — не все платформы и рантаймы позволяют исполнять динамически созданный машинный код.

Набор команд KTemplate

Ранее я говорил, что KTemplate генерирует байт-код. Это не совсем так. Используемое представление лучше называть p-code (почти синоним), так как команды занимают не один байт.

Так как в PHP нет нативных массивов байтов, а использовать строки для этой цели не очень разумно (типа «символ» у нас тоже нет, только строки из одного символа), KTemplate кодирует команды в массивах из int’ов. И в PHP, и в KPHP int занимает 8 байт. В этот размер влезают все необходимые инструкции.

Я рассматривал FFI-массивы в качестве альтернативы, но в PHP
они работают довольно медленно по сравнению с обычными типами.

Может показаться, что это расточительно — использовать 8 байт вместо одного в байт-коде, однако это не совсем так. KTemplate использует регистровую модель виртуальной машины, поэтому практически в каждой команде у нас есть от двух до трёх операндов. В байт-коде это бы уже было 4 байтами. Некоторые команды могут достигать 7 байт из-за дополнительных операндов типа индексов констант.

Приятное свойство этого представления состоит в том, что все команды имеют одинаковую ширину. Весь int целиком мы будем называть opdata — это opcode плюс операнды инструкции. Опкод всегда занимает 1 байт и находится в младшем разряде.

Почти все интерпретаторы байт-кода выглядят как цикл по байт-коду с переключением (switch) по опкоду. Опкод описывает, какую операцию нужно произвести. Примерами опкодов могут быть JUMP, перемещающий курсор интерпретатора (program counter) в другое место внутри байт-кода, и CONCAT, выполняющий конкатенацию указанных аргументов и складывающий результат в описанное инструкцией место (например, регистр виртуальной машины).

Следующее выражение всегда извлекает opcode из opdata:

$opcode = $opdata & 0xff;

Всё остальное внутри opdata — это операнды (аргументы). Несколько примеров операндов:

  • слот (регистр) виртуальной машины (на чтение или запись);
  • индекс константы из пула;
  • непосредственное значение (для малых чисел и данных типа bool).

Большая часть операндов занимает 1 байт, но некоторые могут занимать 2 байта. Разберём инструкцию JUMP_FALSY:

0x29 pcdelta:rel16 cond:rslot

0x29 — это опкод. Затем идёт аргумент pcdelta, занимающий два байта. Последним аргументом идёт индекс регистра-условия (1 байт).

Распаковка всех данных инструкции:

// $pc -- это смещение внутри исполняемого байт-кода
$opdata = $code[$pc];
$op = $opdata & 0xff;
$rel16 = ($opdata >> 8) & 0xffff;
$cond_slot = ($opdata >> 24) & 0xff;

Попробуем представить эти байты инструкции (порядок выглядит обратным из-за особенностей нашего энкодинга):

[cond_slot] [rel16.1] [rel16.2] [op]

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

$cond = $state->slots[$cond_slot + $frame_offset];

А вот реализация опкода JUMP_FALSY:

if (!$cond) {
    $pc += $rel16;
}

Результаты любого выражения, заключённого в {{}}, используются для добавления результата в выходной буфер. Это означает, что мы можем ввести псевдорегистр slot0, который будет неявным и продублировать большую часть команд для поддержки этого аргумента. Сам slot0 будет локальной переменной, доступ к которой будет прямым, без массива.

Предположим, у нас есть следующий фрагмент шаблона:

{{ x ~ y }}

Результатом компиляции было бы что-то такое:

load slot1 $x
load slot2 $y
concat slot1 $x $y
echo slot1 

Введём slot0:

  load slot1 $x
  load slot2 $y
- concat slot1 $x $y
- echo slot1 
+ concat_slot0 $x $y
+ echo_slot0

Получим на две операции с массивом меньше (чтение+запись).

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

Константные данные, например числа и строки, хранятся отдельно от байт-кода, в плоских массивах. Внутри инструкции используется индекс, по которому мы можем найти нужное значение в массиве констант. Одни и те же значения имеют идентичные индексы. Уникальные индексы присваиваются на этапе компиляции шаблонов.

Полный и актуальный список набора команд можно найти в репозитории. Если интересно как именно создаётся этот байт-код, начать можно с src/Internal/Compile/Compiler.php.

Связывание данных

Ни один шаблонизатор не будет полезен, если в самих шаблонах нельзя будет использовать данные.

Когда внутри шаблона встречается выражение типа x или x.y, нужно понять, как извлечь эти значения из контекста исполнения.

Самый наивный вариант — это представлять данные в виде простого массива, по которому мы выполняем поиск. Тогда x будет искаться в $data['x'], а x.y в $data['x']['y']. У этого пути есть несколько недостатков:

  • работать можно будет только с массивами, доступ к объектам не сработает;
  • для запуска шаблона нужно будет собирать данные в такой массив => лишние копирования.

Если же использовать обёртку над доступом по ключу, то можно будет поддержать и объекты. Заменяем прямой поход к массиву на вызов getProp(getProp($data, 'x'), 'y') и готово. Twig делает примерно то же самое.

Внутри функции getProp будет проверяться, что за объект туда передан: массив, объект или что-то иное. В случае объектов потребуется проверка на isset($data->$key) и извлечение через $data->$key. Уже понимаете, к чему я веду? В KPHP такое работать не будет. Да и система типов не позволяет смешивать в массиве примитивные типы вместе с объектами.

Как же здесь справляется text/template из Go? Через рефлексию. Это не очень эффективно, но работает. Вызов функций происходит там через ту же рефлексию, но уже немного по другим причинам. Чтобы, например, пользователь мог привязать функцию с типизированными аргументами, а шаблонизатор как-то смог её вызвать.

В KPHP рефлексии нет. Поддержки $object->$field тоже нет. Как же быть? Ограничиваться массивами не хочется — слишком примитивно и требует копирования данных.

На помощь приходит идея провайдеров данных. Когда шаблонизатор видит ключ x.y, вместо того чтобы попробовать раскрутить его как доступ к полю y из x, он отдаёт связанному провайдеру данных ключ "x.y" целиком. Тот должен сам понять, как этот "x.y" отобразить на данные.

// Интерфейс состоит всего из одного метода!
interface DataProviderInterface {
    public function getData(DataKey $key): mixed;
}

Пример разрешения ключей:

public function getData(DataKey $k): mixed {
    if ($this->matchKey2($k, 'foo', 'bar')) {
        return $this->foo->bar;
    }
    if ($this->matchKey3($k, 'foo', 'baz', 'qux')) {
        return $this->foo->baz->qux;
    }
    // ...обработка остальных ключей
    return null;
}

Пример getData для ArrayDataProvider:

public function getData(DataKey $k): mixed {
    switch ($k->num_parts) {
    case 1:
        return $this->data[$k->part1];
    case 2:
        return $this->data[$k->part1][$k->part2];
    default:
        return $this->data[$k->part1][$k->part2][$k->part3];
    }
}

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

Основным минусом является то, что придётся реализовывать несколько провайдеров данных. В худшем случае — по провайдеру на каждую точку входа для отрисовки шаблонов.

Я как-то обсуждал тему того, как ещё можно реализовать доступ к данным из шаблонов, в подкасте Golang United #23. Возможно, вам будет интересно послушать.

Кеширование извлекаемых данных

Каждое извлечение a.b.c — это вызов интерфейсного метода плюс исполнение самого кода разрешения ключа. Мы ожидаем, что повторное разрешение того же ключа даст нам идентичный результат. KTemplate выполняет кеширование повторных запросов ключа. Первый доступ в дереве отрисовки шаблонов по ключу будет честным. Каждый следующий доступ будет извлекать значение из кеша.

Кеш довольно прост и эффективен. Для определения, есть ли данный ключ в кеше, используется ровно один бит из маски. Сами закешированные значения хранятся в локальных для фрейма слотах («регистрах»). Максимально во фрейме могут кешироваться до 64 ключей.

Ожидаемо, разовый доступ с кешированием работает немного медленнее. Однако уже со второго чтения мы получаем значительное ускорение. Его эффект тем сильнее, чем сложнее процедура разрешения имени. Результаты выше представлены для относительно простой реализации провайдера данных.

Экранирование

text/template выводит текст как есть, без экранирования.

html/template пытается понять, в каком контексте выполняется вычисление выражения. Если внутри атрибута href, шаблонизатор применит url-экранирование. Если внутри тела html-тега, будет использоваться html-экранирование. Семантическое экранирование — это красиво, но оно требует понимания структуры шаблонов.

Twig и KTemplate по умолчанию экранируют всё с помощью escape('html'), но это поведение можно переопределить (в том числе отключить экранирование полностью).

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

Расширяемость

Шаблонизаторы из стандартной библиотеки Go позволяют определять свои функции для вызова из шаблонов. На этом всё.

Twig даёт невероятные возможности для расширения. Можно создавать свои теги, операторы, фильтры, функции… Почти любая ваша фантазия может быть реализована как Twig-расширение (если ваши фантазии связаны с шаблонизацией текста). Twig также поддерживает макросы.

Для KTemplate-шаблонов можно определить функции и фильтры. Поддержки макросов пока нет, но мы добавим её в будущем.

Рендеринг вложенных шаблонов

Twig и Jinja используют наследование шаблонов. В html/template из стандартной библиотеки Go вложенные шаблоны обрабатываются через команды define, block и template (их возможности более ограниченные). KTemplate использует похожую модель.

Каждый шаблон имеет уникальное имя. Используя это имя, мы можем попросить шаблонизатор отрисовать в указанном месте требуемый шаблон с переданными данными. В некотором смысле это эквивалентно вызову функции.

В простейшем случае шаблон не имеет никаких явных аргументов. Он использует только определённые в нём же локальные переменные и внешние данные, получаемые от DataProvider. Параметры шаблонов в KTemplate описываются через {% param %}. Параметры нужны в том случае, когда этот шаблон мы хотим рендерить из других шаблонов, имея при этом возможность его параметризировать.

Параметры определяются в самом верху шаблона:

{% param $name = "button" %}
{% param $label = "" %}
{% if $label %}
<label>
    {{$label}}:
    <input id="ui-{{$name}}" type="button" value="{{$name}}">
</label>
{% else %}
    <input id="ui-{{$name}}" type="button" value="{{$name}}">
{% end %}

Использование этого шаблона из другого:

{% include "ui/button.template" %}
    {% arg $name = "example1" %}
{% end %}

{% include "ui/button.template" %}
    {% arg $name = "example2" %}
    {% arg $label = "Example" %}
{% end %}

Такое использование иногда называют частичными шаблонами (partials). С помощью include мы можем достичь поведения, похожего на наследование шаблонов. Возьмём пример из Twig:

<!-- base.html -->
<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="style.css"/>
            <title>{% block title %}{% endblock %} - My Webpage</title>
        {% endblock %}
    </head>
    <body>
        <div id="content">{% block content %}{% endblock %}</div>
        <div id="footer">
            {% block footer %}
                &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
            {% endblock %}
        </div>
    </body>
</html>

<!-- child.html -->
{% extends "base.twig" %}

{% block title %}Index{% endblock %}
{% block head %}
    {{ parent() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
        Welcome to my awesome homepage.
    </p>
{% endblock %}

А теперь перепишем его на KTemplate:

<!-- base.html -->
{% param $title = "" %}
{% param $head = "" %}
{% param $content = "" %}
{% param $footer %}
    &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
{% end %}

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="style.css"/>
        <title>{{ $title }} - My Webpage</title>
        {{ $head|raw }}
    </head>
    <body>
        <div id="content">{{ $content|raw }}</div>
        <div id="footer">
            {{ $footer|raw }}
        </div>
    </body>
</html>

<!-- child.html -->
{% let $head %}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% end %}
{% let $content %}
    <h1>Index</h1>
    <p class="important">
        Welcome to my awesome homepage.
    </p>
{% end %}

{% include "base.ktemplate" %}
    {% arg $title = "Index" %}
    {% arg $head = $head %}
    {% arg $content = $content %}
{% end %}

Здесь я использовал альтернативный, блочный синтаксис для инициализации переменных.

  • Вместо extends пишем include и вставляем его в конец шаблона.
  • block на стороне дочернего шаблона называется arg.
  • block на стороне родительского шаблона называется param.

include создаёт новый фрейм исполнения, смещая значение $frame_offset на размер текущего фрейма. Стек фреймов умеет расширяться по необходимости.

Декомпиляция шаблонов

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

Декомпилировать сгенерированные исходные коды на Go или PHP не нужно. Это уже исходные тексты, которые можно изучать и отлаживать. А вот байт-код или дерево для исполнения просто так не отобразить без дополнительных инструментов.

KTemplate предоставляет дизассемблер для своих шаблонов:

// "-" около тега удаляет пробельные символы с указанной стороны,
// аналогично это работает в Twig и text/template
$loader = new ArrayLoader([
    'main' => '
      {%- let $x = "abc" %}
      {%- if $x %}
        {{- f($x ~ external_data) }}
      {%- end %}
      {{- external_data -}}
    ',
]);

$engine = new Engine(new Context(), $loader);
$engine->registerFunction1('f', function ($s) {
    return strrev($s);
});

$data = new ArrayDataProvider([
  'external_data' => '123',
]);

$t = $engine->load('main');
$result = $engine->renderTemplate($t, $data);
$decompiled = $engine->decompileTemplate($t);
$disasm = $decompiled->bytecode;

var_dump($result);
var_dump(implode("n", $disasm));

Результатом рендеринга шаблона будет "321cba123".

Содержимое $disasm:

  LOAD_STRING_CONST slot2 `abc`
  JUMP_FALSY L0 slot2
  LOAD_EXTDATA_1 slot4 slot1 external_data
  CONCAT slot3 slot2 slot4
  CALL_SLOT0_FUNC1 *slot0 slot3 f
  OUTPUT_SLOT0 *slot0
L0:
  OUTPUT_EXTDATA_1 slot1 external_data $1
  RETURN

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

       кеш для external_data
       |             
       |             слоты для временных значений
       |             |      
[slot0][slot1][slot2][slot3][slot4]
|             |
|             локальная переменная $x
|
ненастоящий слот, зарезервирован

Кеширование скомпилированных шаблонов

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

Кеширование шаблонов — явление довольно специфичное. Для Go-приложений это не имеет особого смысла. Все шаблоны, как правило, компилируются один раз на старте приложения, а затем используются внутри разных запросов (если речь идёт о каком-то сервере). В случае PHP (и KPHP) модель исполнения иная — и вот здесь мы уже всерьёз можем говорить о кешировании.

Модель кеширования в Twig следующая. Шаблонизатор знает, каким должно быть имя генерируемого класса для отдельно взятого шаблона. Если этот класс уже загружен, то всё отлично, можно исполнять шаблон. Если не загружен, можно попробовать загрузить его из кеш-директории, куда мы складываем сгенерированные классы. Если же и там класса нет, будет производиться компиляция.

KTemplate работает почти по такой же схеме, но вместо PHP-классов мы сохраняем данные шаблонов. Их p-код, константы и метаданные.

Стратегия инвалидации кеша у Twig и KTemplate практически идентичная: по размеру и mtime файла.

Отличия KTemplate от Twig

Строки

В KTemplate нет интерполяции строк, но есть raw string literal. Эти литералы особо полезны для регулярных выражений.

{% if $x matches `/d+/` %}
{# vs #}
{% if $x matches "/\d+/" $}

Локальные переменные

В Twig есть только {% set %}. Нет синтаксического разделения на декларацию и модификацию переменных. Это похоже на то, как ведут себя переменные в PHP, но есть важные преимущества, из-за которых KTemplate использует пару {% let %} + {% set %}:

  • читабельность: становится понятно, где объявлена переменная;
  • ошибки обращения к неопределённым переменным во время компиляции шаблона;
  • нет страха коллизии имён между разными лексическими блоками;
  • более эффективная (и простая) аллокация слотов для короткоживущих переменных.

{% let $x = 10 %}
{{ $x }} => 10

{% set $x = 20 %}
{{ $x }} => 20

Лексический блок в KTemplate создают следующие конструкции: for, if и блочная форма присваивания в let/set/param/arg.

{# Блочное присваивание вводит лексический блок #}
{%- let $x %}
    {%- let $i = "foo" %}
    {{- $i -}}
{% end %}

{# Это уже другая переменная $i #}
{% let $i = "bar" %}

{# Выводит "foo" и "bar" #}
>{{ $x }}<
>{{ $i }}<

Другие различия

В KTemplate не реализованы следующие возможности Twig:

  • именованные параметры при вызове функций;
  • вызов функции без скобочек;
  • теги вроде spaceless;
  • литералы для массивов.

В KTemplate другая модель включения шаблонов и разрешения связанных с шаблоном данных.

Сравнение производительности KTemplate и Twig

Мы написали интерпретатор на интерпретируемом PHP. Какие будут последствия для производительности?

Бенчмарки будем гонять на трёх шаблонах:

$twig_templates = [
    'constant' => 'hello, world',
    'simple' => '
        {{ x ~ y }}
    ',
    'normal' => '
        {% set v = y %}
        {% for item in items %}
            {# comment #}
            {% set s = item ~ x ~ v %}
            {% if item %}
                > {{ s }}
            {% endif %}
        {% endfor %}
    ',
    'nested' => '
        {% include "normal" %}
        {% include "simple" %}
        {% include "simple" %}
        {% include "simple" %}
        {% include "simple" %}
        {% include "simple" %}
        {% include "simple" %}
    ',
];

Данные для шаблонов:

$template_data = [
    'x' => 53,
    'y' => 'foo',
    'items' => [
        'a',
        'b',
        'c',
        '',
        'd',
        'e',
        'f',
        '',
    ],
];

Запускать тесты я буду с помощью ktest. old — это Twig, new — это KTemplate:

name                    old time/op  new time/op  delta
Engine::RenderConstant  2.83µs ± 3%  0.84µs ± 1%   -70.34%
Engine::RenderSimple    3.23µs ± 3%  3.41µs ± 1%    +5.48%
Engine::RenderNormal    10.6µs ± 1%  26.3µs ± 0%  +147.28%
Engine::RenderNested    24.9µs ± 2%  51.4µs ± 3%  +106.46%

Результаты интерпретировать так:

  • Twig работает тем быстрее, чем сложнее шаблон;
  • механизм включения шаблонов в KTemplate довольно эффективен.

Для KPHP мы не можем собрать результаты для Twig. Вместо этого сравним два KTemplate, запущенных на разных языках: PHP и KPHP.

name                    php time/op  kphp time/op  delta
Engine::RenderConstant   841ns ± 1%   513ns ± 1%  -39.03%
Engine::RenderSimple    3.41µs ± 1%  1.53µs ± 0%  -55.16%
Engine::RenderNormal    26.3µs ± 0%   8.4µs ± 1%  -67.82%
Engine::RenderNested    51.4µs ± 3%  14.3µs ± 2%  -72.28%
[Geo mean]              7.88µs       3.12µs       -60.48%

KTemplate на KPHP работает более чем в 2-3 раза быстрее, чем на PHP.

А теперь самое интересное сравнение. Будет ли KTemplate на KPHP шаблонизировать медленнее, чем Twig на PHP?

name                    phh time/op  kphp time/op  delta
Engine::RenderConstant  2.83µs ± 3%  0.51µs ± 1%  -81.92%
Engine::RenderSimple    3.23µs ± 3%  1.53µs ± 0%  -52.70%
Engine::RenderNormal    10.6µs ± 1%   8.4µs ± 1%  -20.41%
Engine::RenderNested    24.9µs ± 2%  14.3µs ± 2%  -42.77%
[Geo mean]              7.01µs       3.12µs       -55.57%

Ответ: нет, не будет. Скорее всего, будет даже быстрее, так как при компиляции KTemplate в C++ мы получаем интерпретатор, написанный на C++, а не на PHP.

Использованная в бенчмарках версия PHP:

$ php --version
PHP 8.1.8 (cli) (built: Jul 11 2022 08:29:57) (NTS)

ktest по умолчанию включает JIT в PHP8+. Оба шаблонизатора в этих бенчмарках использовали закешированный шаблон, сама компиляция шаблона в замеры не попадала. Оба шаблонизатора работали с включённым экранированием со стратегией html.

Настройки JIT, используемые в ktest:

opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=96M
opcache.jit=on

Оптимизации KTemplate

Можно ли сказать, что KTemplate — это эффективный шаблонизатор для PHP? С одной стороны, мы знаем, что он работает медленнее, чем Twig. А с другой, тот разрыв, что мы наблюдаем, гораздо ниже, чем можно было бы ожидать. Всё-таки это интерпретатор внутри другого интерпретатора.

Разберём несколько примеров оптимизаций, которые делает KTemplate, чтобы быстро работать на KPHP и не сильно отставать от Twig при исполнении в режиме PHP.

Конкатенация строк

Допустим, есть некоторое выражение с конкатенацией:

{% let $a = "a" -%}
{% let $b = "b" -%}
{% let $e = "e" -%}
{{ $a ~ $b ~ "c" ~ "d" ~ $e }}

Сгенерированный код будет выглядеть следующим образом:

  LOAD_STRING_CONST slot1 `a` # init $a
  LOAD_STRING_CONST slot2 `b` # init $b
  LOAD_STRING_CONST slot3 `e` # init $c
  LOAD_STRING_CONST slot4 `cd` # const-folded "c" ~ "d"
  CONCAT3_SLOT0 *slot0 slot1 slot2 slot4
  APPEND_SLOT0 *slot0 slot3
  OUTPUT_SLOT0 *slot0

  • Где это возможно и имеет смысл, KTemplate сворачивает константные выражения.
  • Кроме обычного CONCAT, есть ещё версия для трёх операндов.
  • Для уменьшения количества временных строк мы достраиваем результат через APPEND.
  • Всё выражение проходит через slot0 — самый эффективный «регистр».

В этом примере можно было бы вообще всё свернуть в вывод константной строки, но на практике переменные не так часто хранят неизменяемые константные значения.

Слияние инструкций

Часто инструкции, не связанные с выводом результата, вставляются между OUTPUT-инструкциями. Вот пример, демонстрирующий это поведение:

{% let $a = "a" %}
{% let $b = "b" %}
{% let $e = "e" %}
Hello, World!

Наивная кодогенерация выглядела бы так:

  LOAD_STRING_CONST slot1 `a` # init $a
  OUTPUT_SAFE_STRING_CONST `n`
  LOAD_STRING_CONST slot2 `b` # init $b
  OUTPUT_SAFE_STRING_CONST `n`
  LOAD_STRING_CONST slot3 `e` # init $b
  OUTPUT_SAFE_STRING_CONST `nHello, World!`

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

  OUTPUT_SAFE_STRING_CONST `nnnHello, World!`
  LOAD_STRING_CONST slot1 `a` # init $a
  LOAD_STRING_CONST slot2 `b` # init $b
  LOAD_STRING_CONST slot3 `e` # init $b

Это на 2 инструкции меньше. Для стороннего наблюдателя результат исполнения шаблона не изменится, а вот рендерить его стало проще.

Гибридная шаблонизация

Альтернативным решением может быть гибридная шаблонизация, когда на этапе разработки применяется динамический шаблонизатор на PHP, а при подготовке к деплою на KPHP мы используем кодогенерацию. И там, и там шаблоны будут реализовать сгенерированные PHP-классы, но в первом случае будет поддерживаться простое обновление шаблонов «на лету», а во втором случае — нет (шаблоны там будут частью исполняемого файла).

Использовать Twig для такого гибридного решения не получится, так как механизм поиска классов там динамический, через autoloader. Чтобы гибридное решение заработало, нам нужно иметь фиксированные имена классов и какие-то конвенции, по которым они соотносятся с шаблонами.

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

Тайпхинты

Обычно, аккуратно расставлять информацию о типах — это благо. Всем рекомендую.

Однако, в случае PHP есть некоторая цена производительности, которую приходится платить. Чтобы ускорить исполнение на PHP, я перенёс все тайпхинты в phpdoc.

Пара сравнений с конкретными числами:

без тайпхинтов vs с ними

Compiler::Simple   18.2µs ± 2%  20.1µs ± 1%  +10.63%
Compiler::Normal1   248µs ± 0%   275µs ± 2%  +10.95%
Compiler::Normal2   339µs ± 0%   366µs ± 2%   +8.17%

без тайпхинтов vs с ними (string_types=1) 

Compiler::Simple   18.2µs ± 2%  20.2µs ± 1%  +11.16%
Compiler::Normal1   248µs ± 0%   272µs ± 0%   +9.65%
Compiler::Normal2   339µs ± 0%   362µs ± 0%   +6.86%

Как видимо, тайпхинты замедляют код на ~10%. Но это я специально выключил JIT. Есть популярное мнение, что JIT решает проблему тайпхинтов и что они наоборот ему помогают:

без тайпхинтов vs с ними (opcache.jit=on) 

Compiler::Simple   10.2µs ± 1%  11.7µs ± 1%  +14.86%  (p=0.000 n=9+9)
Compiler::Normal1   119µs ± 0%   158µs ± 0%  +33.01%  (p=0.000 n=8+8)
Compiler::Normal2   159µs ± 4%   203µs ± 1%  +27.69%  (p=0.000 n=9+8)

Всё с точностью до наоборот. Со включенным JIT’ом разница между наличием тайпхинтов и их отсутствием ещё более значительна. 20-30% замедления для проекта типа KTemplate ощутима.

Выводы

Ни один из существующих шаблонизаторов для PHP не запустить на KPHP. Как мы сегодня убедились, это ещё не значит, что создать такой шаблонизатор невозможно. KTemplate неплохо работает и там, и там.

Оптимальное решение для реализации шаблонизатора часто зависит от того, на чём мы его реализуем. Если это шаблонизатор для PHP, то делать интерпретатор байт-кода будет не самым производительным вариантом. Тем не менее если мы хотим сохранить возможность AOT-компиляции (не обязательно через KPHP), то стоит подумать об этом заранее.

KTemplate можно попробовать онлайн: quasilyte.tech/ktemplate. Там можно позапускать разные шаблоны, а также посмотреть, во что они декомпилируются. Сайт обслуживается сервером на KPHP, работая на почти самой дешёвой виртуалке от Selectel. Замечу, что KPHP-бинарник я компилировал на своей машине, а потом залил его на виртуалку. При статической линковке количество shared-зависимостей будет минимальным, поэтому можно ставить легковесную систему на виртуалку.

Заинтересовались KPHP? Приглашаю вас в чатик сообщества KPHP!

Как написать продающий текст и привлечь клиентов? Pressfeed разобрал все основные схемы и шаблоны продающих текстов, которые могут понадобиться в работе рекламщику, копирайтеру, редактору или сммщику.

Изображение 1 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

Иллюстрация Екатерины Урусовой

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

Чтобы написать продающий текст «по канону», можно воспользоваться одним из шаблонов — эти схемы проверены временем и протестированы сотнями маркетологов.

Сначала нужно определиться, для какого канала и целевой аудитории предназначено сообщение. Например, текст для рассылки акций по текущим клиентам будет кардинально отличаться от рекламного объявления в Инстаграм по холодной аудитории. 

Чтобы понять, что писать, ответьте на эти вопросы:

  1. Где будет размещаться текст? (сайт, лендинг, рассылка, соцсети, рекламное объявление, буклеты или другие промо-материалы)
  2. Для кого текст (отталкиваемся от характеристики ЦА)? (текущие клиенты / новые пользователи; аудитория, которая знает / не знает о проблеме; человек знаком / не знаком с компанией)
  3. Какая основная задача текста? (указать на проблему и предложить решение, познакомить с компанией / товаром, показать преимущества продукта / бренда)
  4. Какой цели нужно достичь? (получить подписчиков, собрать лиды, продать товар, привлечь внимание к акции)

В зависимости от ваших задач и каналов продвижения, выбираем один из шаблонов.

  1. Классическая схема AIDA и вариация AIDMA
  2. Четыре вопроса
  3. PAS (проблема — внимание — решение)
  4. Формула Джо Витале
  5. PMHS (боль — больше боли — надежда — решение)
  6. 4 U’S (полезность — срочность — уникальность — специфика)
  7. ODS (предложение — дедлайн — действие)
  8. SCH (звезда — цепь — крючок)
  9. FAB (особенности — преимущества — выгоды)
  10. ACCA (осведомленность — понимание — убеждение — действие)
  11. PPPP (картина — обещание — убеждение — действие)
  12. BAB (до — после — мост)

Классическая схема AIDA и вариация AIDMA

Где использовать: для любых каналов — лендинга, сайта, социальных сетей, рекламных объявлений, рассылки и промо-печати.

Шаблон продающего текста

Схема текста: Внимание — Интерес — Решение — Действие

Внимание — рассказываем об УТП, показываем главное свойство продукта или предлагаем скидку, бонусы, акции (для лояльной аудитории, которая знает о вас или продукте).

Интерес — показываем продукт с разных сторон, отвечаем на вопросы: чем товар поможет покупателю, какие от него выгоды можно получить (в том числе и неочевидные).

Решение — отрабатываем негатив и возражения, указываем на то, как преодолеть потенциальные проблемы, приводим аргументы и оправдываем цену.

Действие — призываем перейти на сайт или страницу, сделать заказ, оставить контакты, обратиться за консультацией.

Скачайте прямо сейчас: книга «Как бесплатно продвигать бизнес с помощью СМИ»

AIDMA

Модификация AIDA, в которую перед действием добавляется мотивация (М). В этом блоке мы стимулируем клиентов — рассказываем о спецпредложениях, акциях, скидках, подарках или ограниченных сроках.

Пример продающего текста

Молекулярная кухня у вас дома — научитесь готовить как шеф-повар лучшего ресторана! (Внимание)

Устройте мастер-класс прямо на вашей кухне и проведите время с семьей за новым занятием. Покажите детям, как творится магия, — приготовьте и попробуйте вместе мороженое из авокадо и креветок или апельсиновую лапшу с соусом из малины и базилика. (Интерес)

В наборе вы найдете все нужные инструменты и ингредиенты. Не волнуйтесь, они абсолютно безопасны. Готовить очень просто — мы пришлем вам несколько уроков сразу на почту. (Решение)

Дарим мини-набор каждому новому покупателю до конца года! (Мотивация)

Посмотрите несколько наших мастер-классов по молекулярной кухне — переходите в профиль по ссылке! (Действие)

Четыре вопроса

Где размещать: лендинг, сайт, социальные сети, рассылки, промо-печать.

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

Шаблон продающего текста

Встаем на место потенциального клиента и отвечаем на вопросы:

«Почему ваш продукт мне нужен? Как он может решить мою проблему?»

«Почему я должен купить его именно у вас? Чем вы лучше конкурентов?» 

«Почему эта цена обоснована? Что я получу за эти деньги?»

«Почему я должен купить продукт сейчас, а не потом?»

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

Пример продающего текста

Изображение 2 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

PAS (проблема — внимание — решение)

Где использовать: рекламные объявления, соцсети и рассылки. 

Шаблон продающего текста

Проблема — указываем на боль клиента.

Внимание — рассказываем о последствиях проблемы, негативном результате для клиента (нагнетаем). 

Решение — говорим, как и почему наш продукт может помочь и решить проблему.

Пример продающего текста

Нет времени гулять с собакой? (Проблема)

Ищем мнения представителей бизнеса для РБК, Коммерсантъ и других СМИ. Отвечайте на запрос здесь!

Задерживаетесь на работе, уезжаете в командировку, а ваш питомец страдает дома один? Это может сказаться не только на состоянии квартиры, но и на психике и здоровье собаки. (Внимание)

Сервис «Песики и котики» позаботится о вашем любимце. Мы приедем, выгуляем вашу собаку, поиграем с ней и накормим после возвращения домой. Это безопасно и надежно — все наши сотрудники проходят серьезную проверку и обучение, а вы всегда можете проследить за вашим питомцем по видеозвонку. (Решение)

Формула Джо Витале

Где размещать: сайт, лендинг, социальные сети, рассылки и промо-печать.

Это самая подробная формула продающего текста, ее можно использовать как в полном формате, так и частично.

Шаблон продающего текста

Внимание — привлекаем внимание пользователя с помощью УТП, акций, скидок и других предложений.

Обещание — сделайте предложение, от которого сложно отказаться, опишите выгоды, которые получит покупатель. 

Желание — вызовите эмоции, нарисуйте картинку в настоящем времени: «Представьте, что вы…».

Убеждение — объясните, почему предложение выгодное, а продукт полезный. Аргументируйте позицию и приведите доказательства: отзывы, цифры, фото. 

Диалог — отработайте потенциальные возражения.

Напоминание — еще раз скажите о выгодах, которые получит покупатель.

Действие — предложите перейти по ссылке, сделать заказ, позвонить или забронировать.

Пример продающего текста

Изображение 3 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

PMHS (боль — больше боли — надежда — решение)

Где размещать: сайт, лендинг, социальные сети, рассылка.

Шаблон продающего текста

Если говорить коротко, задача текста — запугать клиента, надавить на больное, а потом обнадежить и предложить решение.

Боль — называем глубинную проблему или страх клиента.

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

Надежда — говорим, что ситуация не безнадежна и все может быть хорошо. 

Решение — предлагаем выход, объясняем, чем наш продукт поможет покупателю.

Пример продающего текста

Постоянно болит голова и спина из-за сидения за компьютером? (Боль)

Вы уже замечаете, что после длинного рабочего дня у вас болит голова, шея, спина, чувствуете упадок сил и отсутствие энергии? 

Неправильно подобранный стул, «кривая» поза и сидячий образ жизни ведут не только к мигреням, но и более серьезным последствиям: искривлению позвоночника, проблемам с давлением и неврозам. (Больше боли) 

Виртуальный пиарщик Pressfeed — подберет СМИ под вашу тему, напишет текст, организует выход публикации или интервью. Оплата за результат!

Чтобы избежать необратимых изменений в организме и снизить негативный эффект для здоровья, нужно правильно организовать рабочее место. (Надежда)

Подберите кресло и стол, за которыми будет действительно удобно работать, — запишитесь на консультацию к специалисту. (Решение)

4 U’S (полезность — срочность — уникальность — специфика)

Где размещать: рекламные объявления, соцсети, рассылка.

Шаблон продающего текста

Полезность — расскажите, в чем польза продукта.

Срочность — ограничение по срокам покупки или количеству товара. 

Уникальность — покажите преимущество компании или продукта, опишите плюсы предложения. 

Специфика — сделайте акцент или разместите дополнительную информацию.

Пример продающего текста

Изображение 4 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

ODS (предложение — дедлайн — действие)

Где размещать: рекламные объявления, промо-печать.

Шаблон продающего текста

Предложение — рассказываем об УТП, акции, скидке, от которых сложно отказаться, 

Дедлайн — ограничение по срокам покупки или количеству товара.

Действие — предлагаем перейти на сайт, купить товар, записаться на консультацию, забронировать место.

Пример продающего текста

Дарим набор новогодних миниатюр при покупке косметики от 1000 руб. (Предложение)

Спешите — акция продлится до конца месяца! (Дедлайн)

Сделайте заказ в онлайн-магазине по ссылке! (Действие)

SCH (звезда — цепь — крючок)

Где размещать: соцсети, рассылка, рекламные объявления.

Шаблон продающего текста

Звезда — УТП, предложение, от которого нельзя отказаться, акции, скидки. 

Цепь — список причин для покупки: рассказываем, что получит клиент, какая выгода для него. 

Крючок — призыв к действию: перейдите на сайт, купите, закажите, подпишитесь. 

Пример продающего текста

Скидка 40% на установку сигнализации для вашего авто. (Звезда)

10 кейсов о росте трафика, продаж и продвижении бизнеса с помощью СМИ. Скачать!

Поставьте новую сигнализацию и будьте уверены в безопасности вашей машины.

  • Автоматическая блокировка дверей
  • Онлайн мониторинг состояния автомобиля
  • Автозапуск двигателя 
  • Функция подключения к камерам (Цепь)

Оставьте заявку прямо сейчас! (Крючок)

FAB (особенности — преимущества — выгоды)

Где размещать: рекламные объявления, рассылка, социальные сети.

Шаблон продающего текста

Особенности — описываем главные особенности вашей компании или продукта.

Преимущества — рассказываем о пользе, преимуществах продукта или компании перед конкурентами.

Выгоды — говорим, какие выгоды получит клиент.

Пример продающего текста

Изображение 5 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

ACCA (осведомленность — понимание — убеждение — действие)

Где размещать: лендинг, сайт, социальные сети, рассылка, промо-печать.

Шаблон продающего текста

Осведомленность — привлекаем внимание (как в AIDA), рассказываем об УТП.

Понимание — приводим доводы, объясняем важность проблемы или ценность предложения. 

Убеждение — доказываем, почему ваша компания или продукт — это хороший выбор, приводим аргументы: цифры, отзывы, кейсы.

Действие — призываем купить, подписаться, сделать заказ, обратиться за консультацией. 

Пример продающего текста

Мы заберем ваш пластик! Green Wave запускает новый проект, который поможет вам стать экологичными. (Осведомленность)

Забота об окружающей среде — это не просто тренд, а обязанность каждого человека. Пластик разлагается дольше любого другого мусора, и каждый год от этих отходов умирают тысячи животных. (Понимание)

Мы понимаем, что не всем легко вести экологичный образ жизни. Поэтому мы решили помочь нашему городу и запустили новый проект #пластикунет.
Мы будем забирать пластик у наших клиентов и сдавать его на переработку, а все деньги пойдут в фонд защиты животных. Все, что вам нужно сделать, — начать сортировать мусор!

За полгода мы собрали уже 4 тонны пластиковых отходов и передали в благотворительный фонд 200 тысяч рублей. (Убеждение)

Присоединяйтесь к нам! Оставьте заявку на участие в проекте под постом! (Действие)

PPPP (картина — обещание — убеждение — действие)

Где размещать: лендинг, сайт, социальные сети, рекламное объявление, рассылка, промо-печать.

Шаблон продающего текста

Картина — позитивное изображение вашего покупателя, товара или услуги.

Обещание — говорим пользователю, что он получит то же, что и на картине.

Убеждение — доказываем клиенту, что ваш продукт — это лучший выбор, приведите отзывы, статистику, фото. 

Действие — призываем купить, подписаться, заказать, оставить заявку, забронировать.

Пример продающего текста

Изображение 6 для статьи Как писать, чтобы продать: 12 шаблонов продающих текстов для сайтов, лендингов, соцсетей, рассылок и рекламы

BAB (до — после — мост)

Где размещать: социальные сети, рассылки, рекламные объявления, статьи.

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

Шаблон продающего текста

До — рассказываем о проблеме, боли клиента. 

После — рисуем картину, в которой эта проблема решена.

Мост — рассказываем, как можно решить проблему и достичь результата. 

Пример продающего текста

Постоянно занимаетесь, но выучить английский никак не получается? (До) 

Спорим, через месяц вы сможете разговаривать на уровне Pre-Intermediate! (После)

У вас все получится, нужно только изменить подход. Участвуйте в марафоне и прокачайте свой английский с лучшими преподавателями нашей школы! (Мост)

#статьи

  • 28 фев 2022

  • 0

Пишем сильный продающий текст: пять главных формул — и советы, как заставить их работать

Как выбрать формулу текста, которая продаст? Как написать лендинг, пост, рассылку? Когда формулы — зло? Разбираем с маркетологами и редакторами.

Иллюстрация: Meery Mary для Skillbox Media

Дарья Чепурнова

Обозреватель Skillbox Media, отраслевой журналист. Работала с TexTerra, SMMplanner, «Нетологией», «ПланФактом», Semantica. Написала больше 60 текстов для рекламных кампаний в «Дзене». Вела нишевой канал на YouTube.

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

Формулы продающего текста — готовые структуры, по которым можно написать пост в социальную сеть, письмо в рассылку, текст для лендинга. В материале разберём:

  • пять популярных формул продающих текстов — от AIDA до QUEST;
  • какие ещё формулы и приёмы можно использовать;
  • насколько эффективны формулы продающих текстов и когда такие шаблоны только вредят.

Чаще всего можно встретить упоминания формул AIDA, PMHS, ODC, DIBABA и QUEST. Разбираем, что входит в структуру текста по ним.

AIDA — это:

  • Attention (внимание). Заголовок и первый абзац привлекают внимание. Например, обещают выгоду или задают цепляющий вопрос.
  • Interest (интерес). Блок пробуждает у читателя интерес к продукту: рассказывает о его функциях или проблемах, которые он решает.
  • Desire (желание). У читателя вызывают желание купить продукт. Описывают выгоды или положительные эмоции, связанные с продуктом.
  • Action (действие). Даётся призыв к действию — зарегистрироваться, купить, позвонить.

Есть расширенные модели формулы AIDA. Например, в структуре по AIDCA есть пункт Confidence (доверие): читателю приводят доказательства качества продукта. В структуре по AIDMA есть пункт Motivation (мотивация) — усиление желания купить продукт. Мотивацией может быть, например, скидка.

Формула AIDA применима почти ко всем форматам продающих текстов. Предприниматель, маркетолог и бизнес-консультант Инна Кармазь говорит, что использует AIDA для постов в Instagram*, прогревов в сторис и лендингов. Иногда формулу разбивают на несколько постов в контентной воронке: в первых прогревают читателей, в последнем — предлагают продукт.

«Контентную воронку, как и формулу AIDA, мы используем преимущественно для работы с тёплым трафиком. Реклама на холодную аудиторию с постом, написанным по формуле AIDA, срабатывала только в случае с дешёвыми и простыми продуктами — например, мылом ручной работы, косметикой, посудой», — уточняет эксперт.

PMHS — это:

  • Pain (боль). Сначала называют боль целевой аудитории, от которой избавляет продукт.
  • More pain (усиление боли). Напоминают читателю, что методы избавления от боли, которые он пробовал, не сработали. Или рассказывают о последствиях: что будет, если ничего не сделать.
  • Hope (надежда). Рассказывают, что решение существует.
  • Solution (решение). Показывают, что избавление от боли — продукт. Могут описать, как именно он поможет закрыть боль.

Формулу часто используют для текстов на начальных этапах воронки продаж, рассчитанных на широкую аудиторию. Например, по ней написаны многие рекламные материалы брендов в «Яндекс.Дзене».

«Надавить на боль — традиционный приём. Формула PMHS отлично работает в рекламных объявлениях, рассылках и лид-магнитах. Например, мы используем сокращённый её вариант для продуктовых баннеров в „Pressfeed. Журнале“ — давим на проблему и быстро предлагаем решение», — говорит редактор сервиса журналистских запросов Pressfeed Валерия Ферцер.

Пример текста по формуле PHMS
Скриншот: страница Pressfeed в Instagram*

ODC — это:

  • Offer (предложение). Текст начинают с предложения продукта. Часто содержит скидку.
  • Deadline (дедлайн, ограничение). Сообщают, что предложение ограничено: товара осталось мало, скидка или сроки предзаказа истекают.
  • Call to action (действие). Призыв к действию — написать, позвонить, купить.

Маркетолог и копирайтер Регина Шагеева говорит, что ODC применима к буклетам, флаерам, баннерам, акциям. Также её можно использовать для вовлечения покупателей в воронку продаж. «Потребитель часто видит формулу ODC и устал от неё. Поэтому тексты по ней должны быть максимально честными и действительно интересными», — предупреждает эксперт.

DIBABA — это не готовая структура, а инструкция к созданию текста. Формула расшифровывается так:

  • Desire (желание). Сначала изучают целевую аудиторию, чтобы выяснить её боли и потребности.
  • Identification (сопоставление). В продающем тексте показывают потребности читателей.
  • Bump (столкновение). Подталкивают покупателя к выводам о том, что продукт стоит купить, — например, рассказывают о преимуществах.
  • ReAction (реакция). Предугадывают возможную реакцию читателя на сообщение и отрабатывают возражения.
  • Buy (покупка). Мотивируют купить — предлагают скидку, рассказывают о сервисе или дедлайне.
  • Atmosphere (атмосфера). Создают удобные условия для покупки: пишут контакты, по которым можно обратиться в компанию, размещают на странице форму заявки.

Формулу DIBABA обычно используют в лендингах — на них оставляют блоки FAQ, в которых отрабатывают возражения целевой аудитории. Также её могут использовать в больших текстах на посадочных страницах или на внешних площадках.

Так может выглядеть отработка возражений
Скриншот: Jetsell

QUEST — это:

  • Qualify (квалификация). Чётко обозначают сегмент аудитории, которому предназначен контент. «Работаете в сфере обслуживания?»
  • Understand (понимание). Показывают, что компания понимает проблемы и потребности аудитории.
  • Educate (обучение). «Обучают», как решить проблемы с помощью продукта, и рассказывают о его пользе.
  • Stimulate (стимуляция). Мотивируют купить продукт — предлагают скидку, говорят о его преимуществах, выгодах.
  • Transition (призыв к действию). Предлагают приобрести продукт или выполнить другое целевое действие.

Формулу используют для посадочных страниц, постов в соцсетях и других форматов контента. Маркетолог и копирайтер Регина Шагеева говорит, что QUEST популярна в лендингах и коммерческих предложениях. Можно разбить работу с аудиторией по формуле на несколько стадий: сделать несколько материалов, писем, сторис. Это один из вариантов прогрева аудитории.

Редактор Pressfeed Валерия Ферцер объясняет главную идею QUEST — подружиться, встать на сторону потенциального клиента и поделиться решением общей проблемы. Именно по этому шаблону работает большинство кейсов. Например, по этой формуле Pressfeed и Tages написали кейс о продвижении в СМИ.

Любую из этих формул можно использовать в постах, на лендингах, в статьях и других форматах, говорит медиаисследователь, секретарь Союза журналистов России и основатель агентства Breaking Trends Юлия Загитова. Разница между форматами в том, сколько текста уйдёт на каждую часть структуры. В коротком формате это может быть пара предложений, а на главной странице сайта — целые блоки или галереи с фото.

Формул продающих текстов много — в разных источниках упоминают 30, 50 и больше готовых структур. Мы спросили экспертов, какие шаблоны, кроме пяти перечисленных выше, они используют.

Редактор Pressfeed Валерия Ферцер рассказала, что в сервисе журналистских запросов используют ещё несколько формул.

В объявлениях и постах часто используют цепочку из выгод. Самая простая формула с такой моделью — SCH. Формула выглядит так:

  • Star (звезда) — УТП, скидка, акция.
  • Chain (цепь) — причины для покупки, выгоды, которые получит клиент.
  • Hook (крючок) — призыв к действию.

Формула SCH отлично подходит для тёплой аудитории и работы с текущими клиентами и подписчиками, говорит Валерия Ферцер. Шаблон не предполагает длинного описания продукта и механики его работы. Поэтому он подходит для аудитории, которая уже знакома с продуктом.

Пример текста по формуле SCH
Скриншот: страница Pressfeed в Instagram*

В текстах Pressfeed также часто встречается формула Джо Витале. Её применяют и в полном, и в сокращённом форматах. Классический шаблон текста по этой формуле:

  • внимание — УТП, акции, скидки или проблема;
  • обещание — предложение, выгоды;
  • желание — картинка, желание пользователя;
  • убеждение — аргументы в пользу продукта или предложения: факты, цифры, фото;
  • диалог — отработка возражений;
  • напоминание — ещё раз о выгодах;
  • действие — призыв перейти по ссылке, сделать заказ.

Порядок смысловых блоков можно менять. Например, поставить убеждение (квалификацию спикера) выше, чем обещание (подтемы эфира), потому что убеждение в этом случае привлекает больше внимания.

Пример текста, написанного по формуле Джо Витале
Скриншот: страница Pressfeed в Instagram*

Маркетолог и копирайтер Регина Шагеева рассказывает, что есть другие формулы:

  • PAS (Problem, Attention, Solution). Она эффективна в материалах, где нужно за короткое время побудить к покупке, — например, в рекламных роликах.
  • CCCC (Clear, Concise, Compelling, Credible). Она подходит для создания лонгридов.
  • «Скопление алмазов». Это перечисление преимуществ, объединённых общим признаком. Эту формулу тоже можно использовать для лонгридов.
  • «Танцовщица с веерами». По этой формуле читателя интригуют деталями, не раскрывая сути предложения. Регина Шагеева говорит, что она эффективна, чтобы направить аудиторию по воронке продаж.

Менеджер по коммуникациям и PR брендингового агентства Depot Дарья Мухина называет ещё два шаблона:

  • PADS (Problem, Agitation, Discredit, Solution). По словам эксперта, шаблон подходит, чтобы выгодно показать ваше предложение по сравнению с конкурентами: акцентируем проблему → агитируем → дискредитируем другие решения → предлагаем своё решение.
  • 4P (Picture, Promise, Prove, Push). Дарья Мухина рекомендует использовать её, если у вас есть козырь в виде отзывов, гарантий. Структура будет выглядеть так: рисуем картинку счастливого будущего → даём обещание → доказываем его → призываем действовать.

В продающих текстах можно также использовать приёмы, которые применяют менеджеры по продажам, говорит Юлия Загитова. Например, психологический приём трёх «да»: задаёте потребителю три вопроса, на которые он ответит положительно, а затем предлагаете товар или услугу. Считается, что после трёх утвердительных ответов человек с большей доли вероятности согласится совершить покупку.

Насколько эффективны шаблоны продающих текстов? Как часто можно их использовать? Почему некоторые считают формулы неэффективными? Мы задали эти вопросы маркетологам, редакторам и копирайтерам.

Насколько эффективны формулы? В Pressfeed не видят большой разницы между эффективностью текстов, говорит редактор сервиса Валерия Ферцер. Она приводит пример. Компания запускала два рекламных объявления: стандартное продуктовое по формуле PMPHS и с текстом «не по шаблону». У объявления без шаблона немного ниже кликабельность — CTR 0,8–1% против CTR 0,9–1,23% у объявления с текстом по формуле PMPHS.

«Можно ли из этого сделать вывод, что без шаблона текст работает хуже? Конечно, нет. У этих объявлений разные креативы, поэтому оценивать только текст в отрыве от изображения неверно», — считает Валерия Ферцер.

Формулы не могут увеличить конверсию в десятки раз, считает контент-директор «Студии Чижова» Сергей Насыров. «По нашему опыту, картинки и формулы влияют на конверсию гораздо меньше, чем сами офферы и то, как выстроена воронка продаж. Поэтому лучше работать над продуктом и воронками», — говорит он.

Как часто их стоит использовать? В Pressfeed формулы продающих текстов используют на сайте, для лендингов и лид-магнитов, в социальных сетях, рекламных объявлениях и даже в статьях.

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

Медиаисследователь, секретарь Союза журналистов России и основатель агентства Breaking Trends Юлия Загитова тоже считает, что не попасть в какую-нибудь формулу вряд ли получится. Вы можете о ней не знать и интуитивно написать так, как вам кажется эффективным. И это будет соответствовать одной из формул.

Фото: Farknot Architect / Shutterstock

«Нет формулы, которая будет работать во всех случаях. Шаблоны — основы, от которых можно отталкиваться. Это не волшебная таблетка, которая продаст всё что угодно», — комментирует она.

Контент-директор «Студии Чижова» Сергей Насыров приветствует эксперименты с формулами, но рекомендует не зацикливаться на них: «Текст должен быть написан на привычном аудитории языке, откликаться на её боли, закрывать возражения и нести пользу. Это самое важное, а какую формулу применили — дело десятое».

Когда формулы продающих текстов — зло? Копирайтер-прототипировщик Евгения Чупина говорит, что структуру каждого текста лучше строить не по формулам, а на основе предпроектного исследования. Важно думать о пользе для читателя и о том, что его интересует в первую очередь: «Иногда нужно поместить отзывы в начале лендинга, иногда — в конце. Аналогично и с другими блоками».

Специалист по лендингам и продающим текстам Дмитрий Исаев комментирует: «Когда автор использует формулы, он пытается загнать оффер клиента в стандартные рамки. Но когда начинается настоящая работа, в большинстве случаев приходится выходить за эти рамки и думать своей головой».

Формулы продающих текстов — зло, считает сооснователь агентства контент-маркетинга «Сделаем» Павел Молянов. «Любые формулы смещают внимание с задачи на процесс. Чтобы создавать эффективные тексты, общайтесь со своей аудиторией, узнавайте, что ей важно, думайте, как доносить свои мысли, тестируйте гипотезы», — советует он.

Универсального шаблона структуры для текстов нет, добавляет Павел Молянов. Структура зависит от цели текста, теплоты трафика, осведомлённости аудитории о бренде и многих других факторов. «Общие советы по подготовке текстов: идти от знакомых понятий к незнакомым, ставить всё самое важное на видное место и не скакать с одной мысли на другую, чтобы не запутать читателя», — говорит он.

Менеджер по коммуникациям и PR брендингового агентства Depot Дарья Мухина рассказывает, что она определила для себя важные составляющие продающих текстов. Среди них — понимание проблем и болей целевой аудитории, применение социальных доказательств и акцент на решающих для покупателя факторах. Эти пункты нужно учитывать вне зависимости от того, используете ли вы формулы.

Формулы продающих текстов — готовые структуры контента. Есть много шаблонов, самые популярные — AIDA, PMHS, ODC, DIBABA и QUEST.

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

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

Что ещё почитать в Skillbox Media о работе с текстом

* Решением суда запрещена «деятельность компании Meta Platforms Inc. по реализации продуктов — социальных сетей Facebook* и Instagram* на территории Российской Федерации по основаниям осуществления экстремистской деятельности».

Научитесь: Профессия Копирайтер с нуля до PRO
Узнать больше

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

Запишитесь на уроки «Школы копирайтинга«

шаблон продающего текста

Весь копирайтинг основан на продажах товаров, услуг или знаний.

Тексты коммерческих предложений, продающие лендинги и PR-статьи востребованы постоянно. При этом оплачиваются по высокому тарифу. Безусловно, они должны быть грамотными во всех отношениях.

Жмите на картинку!

shablon-prodayushego-teksta

Современный темп жизни основан на принципе — действовать здесь и сейчас. Поэтому начните зарабатывать, попутно обучаясь.

Посмотрим на разные варианты одного и того же текста.

Изучите готовый шаблон продающего текста и действуйте

Эта фраза для классического продающего текста. В нее включены глаголы побудительного наклонения: получите, действуйте. Цель — вызвать у покупателя желание немедленно сделать заказ.

Профессиональные продающие тексты всегда несут гарантии коммерческой отдачи.

О том, как создается продающий текст, читайте здесь.

Шаблон продающего текста в классическом варианте.

Любая коммерческая статья — это, своего рода, новость, рекламный ход, скрытое или открытое привлечение клиентов. Значит, как и любая новость, интонационно она часто подается в абстрактной форме перевернутой пирамиды.

Схема пирамиды продающего текста

Лид. Вступление.

Сначала — вызвать «Ах!» Первый вступительный абзац называется лид. Он призван возбудить и удержать интерес читателя с помощью разных приемов. 

Вначале выдается основная новость, суть статьи в виде заманчивого предложения, интригующего вопроса, сенсации. Сразу обозначается проблема потенциального клиента (ЦА) и намек на способ ее решить.

Например:

«Необычный подарок, который поразит вашего ребенка и надолго отвлечет от компьютера.. (заголовок статьи Н1)

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

Это волшебная 3D ручка для творчества.»

Тело. Обозначение проблемы.

В следующем блоке продающего текста мы усиливаем акцент на проблеме потребителя, потенциального клиента, описывая лишние растраты, нехватку времени, негативные эмоции, которые приходится испытывать при отсутствии вашего товара.

Например:

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

Как найти ребенку более интересное занятие?

Что противопоставить умным и хитрым гаджетам?

Мы нашли способ порадовать ваших детей!»

Список в теле статьи.

В средней части текстовой пирамиды раскрываются детали товара, его преимущества в виде четкого списка, удобного для восприятия читателем. Перед блоком списка можно удачно вписать подзаголовок Н2, Н3, Н4 с ключевым словом статьи.

«3D ручка — фантастический гаджет XXI века» (подзаголовок статьи Н2).

Доказательства

В следующих 2-3 абзацах описываются доказательства надежности товара. Уместны примеры успешного использования, точные цифры полученный результат. 

Например:

«Джек Николсон, Холли Бэрри, Мадонна и даже ваша соседка Марина — уже давно купили новые супер-тапочки Crocs Sport Slip. А у вас еще нет этой новинки?» (подзаголовок Н3)

Выводы

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

Например:

«Покупая продукцию у нас, вы заплатите в 3 раза дешевле. Наш консультант подскажет, как более выгодно использовать наши услуги.»

Призыв

Последняя фраза на десерт — выражает конкретный призыв к действию с глаголами повелительного наклонения. Эта форма глагола побуждает сделать покупку без промедления и лишних раздумий.

Например:

«Еще остались вопросы?  Ограничены в бюджете? Свяжитесь с нами прямо сейчас и узнайте, как сэкономить!»

7 блоков шаблона продающего текста:

  • Интрига (в заголовке)
  • Проблема (потребности клиента)
  • Предложение (решение проблемы)
  • Выгоды для клиента (список)
  • Преимущества и свойства (список)
  • Доказательства (точные цифры)
  • Призыв (побуждение к действию)

Этот список можно назвать универсальной схемой, шаблоном стандартного продающего текста.

Успехов, коллега!

Хочу получать свежие статьи на почту!

Генерация текста для начинающих и не только

Категория:
Фундаментальные статьи
– Автор:
Игорь (Администратор)
  • Генерация текста зачем она нужна?
  • Размножение статей — что это?
  • Основные конструкции в генераторах
  • Какие алгоритмы используются для оценки текста
  • В чем отличие шаблонов товаров и статей?
  • Как создать свой первый шаблон
  • Наиболее частые ошибки составления шаблонов и размножения статей

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

Однако, только этим примером генерация текста не ограничивается. Этот процесс включает в себя также генерацию псевдоуникальных текстов. Но, обо всем по порядку.

Генерация текста зачем она нужна?

Генерация текста для начинающих и не только

Как вы наверное уже поняли, сегодня, практически каждый сайт это продукт процесса генерации текста. Однако, есть области, где генерация минимальна, например, у статейных сайтов, где основной текст на странице каждой статьи составлен человеком и уникален (относительно уникален). А есть области, где без генерации основного текста попросту не обойтись, так как написание интересных и удивительных текстов для каждого случая просто не оправдано (слишком много времени уйдет, а результат будет минимальным). Такими примерами являются каталоги программ, интернет-магазины, статейное продвижение и прочее.

Просто представьте, что у вас есть 1000 товаров, которые практически ничем не отличаются друг от друга, только несколькими параметрами. Написать 1000 уникальных статей просто нереально. Любой, кто хоть раз написал нормальную статью знает, что в среднем на нее может уходить от часа и до бесконечности. Простая математика. Если в день писать 8 статей, каждая из которых будет занимать не менее часа вместе с оформлением, то вам понадобится порядка 125 дней. Больше трети года, которые можно пустить на что-то более полезное.

Однако, важно понимать, что генерация текста подразумевает аккуратность и вдумчивое использование, так как поисковые системы не нацелены на захламление своей выдачи. От того, как вы подойдете к процессу, будет зависеть результат. Позиции сайта по запросам могут подняться, трафик увеличиться, поведенческие факторы улучшиться и так далее. А может и наоборот приведет к применению фильтров со стороны поисковых систем вплоть до АГС и прочего.

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

Размножение статей — что это?

Сегодня, существует более 1 млрд сайтов. Просто вдумайтесь в эту цифру. И на каждом из них далеко не по одной странице. Все эти сайты поисковикам необходимо ранжировать в поисковой выдаче по такому же количеству запросов (в сравнении по порядку). Задача крайне объемная. Поэтому учитывается масса факторов, которые постоянно ужесточаются. К примеру, от года к году увеличивается число необходимых ссылок на сайт для получения определенного ТИЦа.

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

Что подразумевает под собой размножение статей? Если говорить простыми словами, то процесс состоит из нескольких шагов:

  1. Составление обычной статьи
  2. Вставка специализированных конструкций, которые позволяют видоизменять текст
  3. Указание параметров для оценки схожести и количество необходимых статей
  4. Генерация

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

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

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

Основные конструкции в генераторах

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

Их всего пара, рассмотрим вначале их:

1. Синонимайз. Под данным термином понимают процесс замены слов на похожие по смыслу или же просто случайную подстановку (четкого критерия тут не существует). Сама конструкция представляет собой открывающую фигурную скобку «{«, затем идут слова или предложения разделенные горизонтальной чертой «|«, а в конце идет закрывающая фигурная скобка «}«.

Рассмотрим следующий шаблон:

Вы получите этот товар вместе с { скидкой | подарком | акцией | 10%-й бонусной картой}

На выходе будут получаться случайным образом следующие строки:

...
Вы получите этот товар вместе с скидкой
Вы получите этот товар вместе с 10%-й бонусной картой
Вы получите этот товар вместе с подарком
Вы получите этот товар вместе с акцией
...

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

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

2. Перестановка. Данная конструкция позволяет перемешивать слова и фразы. Она встречается практически во всех программах и сервисах генерации текста, но ее наличие не является обязательной. Перестановка очень полезна в случаях, когда необходимо переставлять местами предложения или же описания чего-либо. Конструкция похожа, но с некоторыми отличиями. Начинается с прямоугольной скобки «[«, затем через горизонтальную черту «|» указываются слова и фразы для перестановки, и в конце идет закрывающая фигурная скобка «]«. Важное замечание. В зависимости от версий программ и сервисов, такие конструкции могут быть немного видоизменены, например, добавляется возможность указывать символы или слова, которые будут разделителями, чтобы их не перечислять.

Рассмотрим пример:

Эта программа позволяет [ просматривать видео, | прослушивать аудио, | вставлять комментарии,] редактировать подсветку

На выходе у вас будут следующие случайные фразы:

...
Эта программа позволяет просматривать видео, прослушивать аудио, вставлять комментарии, редактировать подсветку
Эта программа позволяет прослушивать аудио, вставлять комментарии, просматривать видео, редактировать подсветку
Эта программа позволяет просматривать видео, вставлять комментарии, прослушивать аудио, редактировать подсветку
...

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

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

1. Вставка. Когда у вас есть какие-то заготовки или же информацию можно взять из какой-либо базы данных, то их можно использовать с помощью конструкций вставки. Обычно, вставка представляет собой некоторое специализированное слово, справа и слева от которого стоят скобки или их комбинации. Например, «[name]«, «{family}«, «[[nick]]» и прочие. Формат зависит от программы, но смысл обычно одинаковый.

Рассмотрим пример. Допустим вам нужно сгенерировать тексты для пользователей:

Уважаемый [name], пожалуйста, подтвердите ваш заказ с номером [order_num]

На выходе для каждого пользователя вы получите тексты вида:

...
Уважаемый Василий, пожалуйста, подтвердите ваш заказ с номером №123
Уважаемый Проськин, пожалуйста, подтвердите ваш заказ с номером №444
...

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

2. Условные функции. Это некоторые специализированные конструкции, которые позволяют логически вычислить какой необходимо текст вставлять (или не вставлять). К примеру, функции проверки значений: равно, больше, меньше и так далее. Формат этих функций уникален в каждом генераторе, поэтому их невозможно перечислить. Однако, они очень полезны в случаях, когда шаблон составлен под разные области, слабо друг от друга отличающиеся. Тем не менее, такие функции встречаются достаточно редко.

Какие алгоритмы используются для оценки текста

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

1. Прямое сравнение. Как и следует из названия, речь идет о том, насколько тексты получились идентичными. При этом важно понимать, что если вы ставите слово вначале текста, то это не сделает его уникальным. Так как остальная часть будет полностью совпадать. Плюс этого метода заключается в простоте понимания, минусом же является то, что с точки зрения поисковых систем это слабый показатель. К примеру, вы можете просто переставить фрагменты текста и у вас получится уникальная статья, но вот поисковик ее воспримет не как уникальную.

2. Метод шинглов. Этот алгоритм является одним из методов оценки текста поисковыми системами. Он не является полноценным, но и поисковые системы не стремятся раскрывать свои алгоритмы, чтобы сохранить выдачу в нормальном состоянии. Тем не менее, этот метод часто применяется для оценки схожести текста и дает весомые результаты.

Его суть заключается в том, что задается некоторое число слов, идущих подряд. Затем весь текст разбивается на фрагменты по этому количеству слов. При этом сдвиг происходит не на указанное количество слов, а каждый раз на одно слово. Полученные шинглы шифруются определенным образом для экономии места. А в последствии два текста сравниваются именно по количеству шинглов, а не по самому тексту. Такой подход сводит на нет перестановку фраз и предложений в тексте, так как от того, что вы поменяли местами два предложения, шинглы практически не изменятся.

Рассмотрим текст.

Цена товара составляет Х с учетом акции.

Для примера возьмем число слов равное 3. В таком случае будут получены шинглы

Цена товара составляет
товара составляет Х
составляет Х с
Х с учетом
с учетом акции.

Теперь, если вы перенесете часть «С учетом акции», добавите слова и получите «С учетом акции цена супер товара составляет всего X», такая фраза будет все равно иметь процент схожести, так как некоторые шинглы все же встречаются. При проверке на прямое совпадение эти два предложения были бы практически разными.

Важно понимать, что это простой пример и что у метода шинглов существует множество вариаций. Чистка от стоп слов — неинформативные слова, такие как предлоги «в», «на» и так далее. У слов убираются окончания. Порядок слов в шингле может иметь или не иметь значения. Слова оцениваются вместе с синонимами. И так далее.

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

В чем отличие шаблонов товаров и статей?

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

Поблажки к описаниям товаров обычно следующие:

  • Снижен критерий минимального количества символов в тексте (по разным данным минимум от 300 до 1000 символов, у статей сегодня этот порог 1500-2500)
  • Поисковики легче относятся к дублированию контента (не только на разных сайтах, но и в рамках одного сайта, например, похожие товары с похожим описанием)
  • Поисковые системы больше ориентируются на другие показатели и отдельные данные, такие как ключевые слова (производители, характеристики, модель и прочее)

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

Как создать свой первый шаблон

Прежде всего, если вы создаете шаблон для сайта или интернет-магазина, то необходимо сделать его бэкап. Шаблоны написать вы всегда успеете, а вот после экспериментов восстановить описания сотням товаров весьма непростое занятие. Следующее, что вам нужно знать, если вы еще ни разу не создавали шаблоны, то начинайте с небольших задач или малых объемов. Не стоит браться сразу за все товары на сайте. Вам вначале нужно увидеть собственными глазами как это выглядит и какой получается результат.

Теперь, после предупреждений, перейдем к небольшому алгоритму создания первого шаблона:

1. Открываете поисковую систему, ищите там описания похожих товаров и статей. На основе этих данных составляете свою статью, только хорошую и не похожую как две капли воды на источники.

2. Начинаете наполнять текст специализированными конструкциями, такими как синонимайз, перестановка, вставка, условные функции (смотря какие из них доступны).

3. Проводите генерацию текста.

4. Проверяете насколько тексты получились уникальными. Можно использовать программы или сайты копирайта, коих достаточно в интернете. Если вы используете для проверки программы и метод шингла, то стоит устанавливать число слов в районе 5-7, лучше 5, но не всегда подходит.

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

6. Получаете готовый шаблон. Обязательно его сохраните куда-нибудь.

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

Наиболее частые ошибки составления шаблонов и размножения статей

А теперь, вам стоит узнать наиболее частые ошибки новичков при составлении шаблонов и размножении статей, чтобы избежать как можно больше грабель:

  • Я сделаю универсальный шаблон на все случае в жизни. В действительности, такое может быть и результаты могут быть хорошими, но новичкам лучше этим не заниматься поначалу. Какие тут подводные камни. Первый. Шаблон вырастет и вы запутаетесь в конструкциях. Не смотрите на те примеры, что были в статье. Обычно, шаблоны представляют собой нечто напоминающее хаос символов и одни конструкции. Второй. Если у вас изменится потребность для части текстов, то вам придется либо еще усложнять шаблон, либо заниматься копированием и переделкой этого универсального шаблона. Третий. Если у вас немного опыта, то легко можно не учесть контекст и получить на выходе читаемый, но бессмысленный текст. В общем, на начальных этапах проблем будет куда больше.
  • А возьму-ка я готовую базу синонимов. Базу синонимов можно использовать, но не бездумно. Все такие тексты после генерации необходимо проверять на читаемость. «А у вас молочный продукт быстро шел» — это не фраза из мультика про Карлсона.
  • Буду сразу составлять шаблон. Этому еще нужно научиться — видеть за шаблоном текст. Новичок уже к половине текста начнет путаться и не понимать, какой он текст составляет. В итоге, шаблон придется не только доводить до нужного процента схожести, но и делать из него текст.
  • Напихаю-ка я ключевых фраз и прочих примочек. Помните, что размноженные тексты так же должны соответствовать нормам сео текстов. От того, что статьи получились уникальными, не значит, что такие статьи нормально войдут в поисковую выдачу. Поэтому следите так же и за остальными аспектами сео. Например, не перебарщивайте с ключевиками, используйте непрямые вхождения и прочее.
  • О придумал что-то еще, перегенерую-ка я весь ассортимент. Помните, что частая смена текстов, тем более в огромных количествах, это сигнал для поисковых систем. Кроме того, если в шаблонах используется синонимайз, то каждый раз будут подставляться случайные слова и фразы, что будет менять текст. Старайтесь подходить к этому вопросу обдуманно. К примеру, если вам нужно добавить что-то в конец текстов, то посмотрите нет ли возможности в вашем генераторе создать такой шаблон, который бы вначале вставил существующий текст, а затем добавил вашу задумку. К таким изменениям в текстах поисковые системы относятся гораздо легче, так как подразумевается, что любые описания могут дополняться со временем (но не полностью видоизменятся, особенно с использованием синонимов).
  • О сразу после генерации по одному шаблону, трафик резко поднялся, сделаю быстренько остальные. Важно понимать, что процессы оценки текстов и сайтов у поисковых систем достаточно медленные. Поэтому вполне возможно, что подъем был связан с чем-то другим. Не торопитесь прогонять все тексты сразу, особенно если вы не уверены в качестве шаблонов. Наблюдайте за тем, что будет происходить. Так же рекомендую при первых признаках снижения не пытаться сразу откатить все назад. При изменении выдачи, на сайте может наблюдаться временный провал в трафике.

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

☕ Понравился обзор? Поделитесь с друзьями!

  • Температура процессора

    Температура процессора
    Фундаментальные статьи

  • Риски использования криптографической защиты информации

    Риски использования криптографической защиты информации
    Фундаментальные статьи

  • Информационная безопасность и защита информации простыми словами

    Информационная безопасность и защита информации простыми словами
    Фундаментальные статьи

  • Монополия, демпинг, клоны в программной среде

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

  • Достоинства и недостатки: почему найти их можно только в обзорах и аналитиках?

    Достоинства и недостатки: почему найти их можно только в обзорах и аналитиках?
    Фундаментальные статьи

  • Подбираем решение или вопросы, на которые должны быть ответы

    Подбираем решение или вопросы, на которые должны быть ответы
    Фундаментальные статьи

Добавить комментарий / отзыв

Понравилась статья? Поделить с друзьями:
  • Как найти площадь фигурный
  • Как найти кейс от наушников джибиэль
  • Как найти картинки одного цвета
  • Как найти прибыль в кафе
  • Как составить электрическую схему устройства