Elementor Addon. Пишем кастомный виджет к билдеру

Elementor – популярный wp плагин для построения страниц; данный тип плагинов называют pagebuilder. Это плагин(как и все в его категории) оперирует специальными виджетами – именно его я и создам, по ходу статьи…

Содержание

Предисловие

Здесья расскажу о том, что толкнуло меня на создание виджета(помимо получения опыта для написания этой писульки). Дело было так: была страница на которую выводилось видео с YouTube. К нему был список тайм-кодов, клик по которым включал воспроизведение видео с определенного момента. Временная метка(таймкод) состоит из самого времени, картинки и текста-описания. При переезде страницы на Элементор – всё взаимодействие сламалось. Задача: создать аддон к Элементор, добавляющий эти возможности в виджете.

Немного воды…

Всем, кто знаком с веб-программированием, с ходу стало понятно в чем причина – javascript; теперь для тех, кто незнаком: за прослушивание всех событий в браузере отвечает javascript. И правда, билдер изменил структуру DOM-дерева страницы и, за часик(долго разбирался в новой структуре), изменив селекторы в скрипте все заработало…

И что ж?.. на этом все? Было бы всё, если бы владелец не сказал, что неудобно так: строить ряд, в нем колонки с текстовым полем в(которых снова ряды с колонками) – сделай-ка единым блоком, чтоб в элементы управления просто вбить значения.

Приступим…

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

add_action('elementor/init', function () {
    add_action('elementor/widgets/widgets_registered', function () {
        require_once(__DIR__ . '/class-youtube-widget.php');
        ElementorPlugin::instance()->widgets_manager->register_widget_type(new Elementor_YouTube_Widget());
    });
});

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

Плагин Элементор имеет свои хуки, позволяющие получить доступ к разным классам его ядра:

  • elementor/init – ко всем;
  • ementor/widgets/widgets_registered – к классу ElementorWidget_Base(и прочим, необходимым для создания нового виджета);
  • elementor/controls/control_registered – к классу ElementorControl_Base(и прочим, необходимым для создания нового типа контролера для плагина);

Это все хуки, которые нужно знать, для того чтоб построить свой виджет. На деле, из-за довольно широкой палитры встроенных контролей, 3ий хук я никогда не использовал – не было нужды создавать свои контроллеры.

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

Теперь немного о самом скрипте – в нем я буду использовать YouTube Iframe Player API. Начнем с html-разметки, которую будем строить на странице

        <section>
            <h2>{{ section_title }}</h2>
            <div class="elementor-row {{ video_position }}" data-id="{{ video_id }}">
                <div class="elementor-column frame-container">
                    <img src="https://img.youtube.com/vi/{{ video_id }}/hqdefault.jpg" class="youtube-preview" alt="Video Preview">
                </div>
                <div class="elementor-column">
                    {{ timestamps_loop }}
                        <figure class="stamp">
                            <img src="{{ timestamp_image_url }}" alt="Stamp Icon">
                            <span class="timestamp">{{ timestamp_time }}</span>
                            <span class="description">{{ timestamp_description }}</span>
                        </igure>
                    {{ endloop }}
                </div>
            </div>
        </section>

Думал использовать Iframe API, но глянув, что он делает – послал его лесом. Дело в том, что беглый анализ кода показал, что апи содержит методы постройки тега iframe с его атрибутами; учитывая, что страница индексируемая(должна быть оптимизирована под скорость загрузки) я решил не захламлять ее дополнительной библиотекой(jquery и так хорошо выполняет эту задачу). В общем, вот скрипт для работы с метками с вышеприведенной разметкой

(function($) {
    'use strict';

    $(document).on('click', '.youtube-preview', function() {
        var id = $(this).closest('.elementor-row').data('id');

        YTFrame.build(id, 0, $(this).parent());
    });

    $(document).on('click', 'figure.stamp', function() {
        console.log(this);
        var id = $(this).closest('.elementor-row').data('id'),
            time = $(this).find('.timestamp').text().split(':'),
            seconds = 60 * parseInt(time[0]) + parseInt(time[1]);
        console.log($(this).closest('.elementor-row').find('.frame-container')[0]);

        YTFrame.build(id, seconds, $(this).closest('.elementor-row').find('.frame-container')[0]);

    });

    var YTFrame = {
        build: function(id, seconds, container) {
            var iframe = document.createElement('iframe');

            iframe.src = 'https://www.youtube-nocookie.com/embed/' + id + '?autoplay=1&start=' + seconds;
            $(container).html(iframe);
        }
    }
})(jQuery);

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

Доделываем

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

<?php

use ElementorControls_Manager;
use ElementorWidget_Base;
use ElementorUtils;
use ElementorRepeater;

Теперь создадмим сам класс со следующими методами

<?php
class Elementor_Test_Widget extends ElementorWidget_Base {

	public function get_name() {}

	public function get_title() {}

	public function get_icon() {}

	public function get_categories() {}

	protected function _register_controls() {}

	protected function render() {}

	protected function _content_template() {}

}

Первые 4 методы просто возвращают по строке. Метод render() строит разметку в редакторе(с приметкой) и на сайте

    protected function render()
    {
        $settings = $this->get_settings_for_display();
        $this->add_inline_editing_attributes('title', 'advanced'); ?>
        <section>
            <h2 <?php echo $this->get_render_attribute_string('text_attr') ?>>
                <?php echo $this->get_settings('title') ?>
            </h2>
            <div class="elementor-row  <?php echo esc_attr($settings['video_position']) ?>" data-id="<?php echo esc_attr($settings['video_id']) ?>">
                <div class="elementor-column frame-container">
                    <img src="<?php printf('https://img.youtube.com/vi/%s/hqdefault.jpg', esc_attr($settings['video_id'])) ?>" class="youtube-preview" alt="Video Preview">
                </div>
                <div class="elementor-column">
                    <?php foreach ($settings['timestams_repeater'] as $key => $value): ?>
                        <figure class="stamp">
                            <img src="<?php echo esc_url($value['stamp_image']['ur']) ?>" alt="Stamp Icon">
                            <span class="timestamp"><?php echo esc_html($value['time_stamp']) ?></span>
                            <span class="description"><?php echo esc_html($value['stamp_description']) ?></span>
                        </igure>
                    <?php endforeach; ?>
                </div>
            </div>
        </section>
        <?php
    }

Здесь Widget_Base->get_settings_for_display() это получение настроек виджета, которые я создам в следующем методе.

Метод _register_controls() отвечает за создание контролей виджета в сайдбаре редактора – здесь немного поподробней. Все настройки растоложены в 3х табах – контент, стиль и дополнительные(их не трожь – они всегда дефолтные!). чтоб выбрать таб нужно в этом методе написать

        $this->start_controls_section(
            'content_section',
            [
                'label' => __('Video'),
                'tab' => Controls_Manager::TAB_CONTENT,
            ]
        );

затем следует открывающий и закрывающий секцию настроек код

        $this->add_control(
            'title',
            [
                'label' => __('Section Title'),
                'type' => Controls_Manager::TEXT,
                'input_type' => 'text'
            ]
        );

        $this->end_controls_section();

и уже между этими тегами можно писать свою настройку.

Вся “слоенка” будет выглядеть так

        // указание на таб
        //  если TAB_CONTENT поменять на TAB_STYLE
        // будет запись в стиль-таб 
        $this->start_controls_section(
            'content_section',
            [
                'label' => __('Video'),
                'tab' => Controls_Manager::TAB_CONTENT,
            ]
        );

        // открытие новой секции
        $this->add_control(
            'title',
            [
                'label' => __('Section Title'),
                'type' => Controls_Manager::TEXT,
                'input_type' => 'text'
            ]
        );


        // настройка в секции, их может быть много
        $this->add_control(
            'video_id',
            [
                'label' => __('Video ID'),
                'type' => Controls_Manager::TEXT,
                'input_type' => 'text'
            ]
        );

        // закрытие текущей секции, но не таба!
        // после этого можно открыть новую секцию
        // она будет в том же табе
        $this->end_controls_section();

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

Наверняка внимательный читатель не только статьи но и кода, заметил в рендеринг-методе эти строки

$this->add_inline_editing_attributes('title', 'advanced');
$this->get_render_attribute_string('title');
$this->get_settings('title');

все они не имеют смысла без метода _content_template(). Поясню: виджет элементор – блок визуально редактируемый; это значит его можно редактировать в поле редактора, а не в сайдбаре. Кароч, 1ая строка это указатель на то, что эта настройка имееит возможность визуального редактирования; 2ой – получает набор классов для того чтоб javascript элементора взял под контроль этот тег; 3я – получает само значение настройки. В случаи с ‘advanced’ можно увидеть расширенную панель редактирования текста

расширенная панель редактирования текста
расширенная панель редактирования текста

Однако, чтоб все это сработало – необходим вышеуказанный метод с следующими строками

<# view.addInlineEditingAttributes( 'title', 'advanced' ); #>
<div {{{ view.getRenderAttributeString( 'title' ) }}}>{{{ settings.title }}}</div>

Заметь(!) эти строки должны выводиться, тк они будут вставлены в backbone-шаблоны(документация по ним). 2ая строка это т, что в окне редактора будет вставлено вместо редактируемой строки.

Заключение

Было разработанное расширение для Элементор. Код сможешь глянуть здесь, конечно он не полный(я удалил из него интеграции с другими плагинами, кастомными плагинами и сократил дерево настроек). Больше примеров ты увидишь в самом Элементор, ну а я попытался немного объяснить – что и как там работает.

Блокчеин, крипта и майнинг – технический взгляд на вопрос

Начало 2021 года… курс биткоина перевалил 40К долларов…. однако здравствуйте! В связи с очередной волной криптохайпа на рынке, решил я начеркать эту статейку – о крипте с технической стороны. С финансовой стороны(точнее мое, обывательское, отношение к ее ценности) – крипта такой же финансовый инструмент, как и доллар США. Объясню: ныне, доллар это цифра, сила которой обеспечена гарантиями правительства(системы) США. Крипта – это такая же цифра, обеспечена гарантиями системы, в которой она хранится – блокчейном. Ценность любого ресурса, в конце-концов, определяют люди. На этом, перейдем к сути статьи…

Содержание

Технический базис

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

  • независимо от длины входящей строки – хеш-код имеет строго определенную длину;
  • имея хеш невозможно восстановить исходную информацию;
  • результат хефирования идентичных строк идентичный;
  • один хеш может иметь только одну исходную строку.

Как, я думаю всем понято, последнее утверждение, теоретически, бессмысленное; поскольку, пул символов ограничен и их количество в хеш-строке также. Но я сказал теоретически – поскольку это число(вариантов комбинаций) велико(для алгоритма SHA-256, в биткоин, их аж 2 в 256-ой степени).

Блокчейн

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

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

Теоретический взгляд

Данная схема хранения данных предусматривает зависимость каждого следующего блока данных от предыдущего, с английского – “цепочка блоков”. Кроме того, для пущей безопасности, блокчейн делают децентрализованным – т.е. копия БД и сопровождающее ее ПО хранятся у каждого, кто использует данную сеть, и все они равноправны.

Децентрализованный блокчейн могут подменить только >50% пользователей этой системы, с одинаково сфальсифицированными блоками.

Майнинг

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

Теория

В целом, майнинг с точки зрения блокчейна – это процесс упаковывания транзакций в блоки; для майнера же, это процесс добычи крипты + получение комиссии с каждой упакованной операции.

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

Рассмотрим на примере Биткоина. Первоначально, с полученных транзакций формируется дерево Меркла(о нем – ниже); после, берется корень этого дерева, конкатенируется с хешом предыдущего блока и случайной строкой(nonce-field); из полученной строки создается хеш и проверяется его сложность: если она выше, чем требует блокчейн для нового блока – составляется новый nonce-field и процесс повторяется, в ином случаи – создается новый блок, о чем оповещаются все майнеры.

Биткоин-блокчейн пересчитывает сложность хеша каждые 2016 блоков таким образом, чтоб процесс нахождения nonce-field(а соответственно, и создание блока) был равен 10 минутам.

Дерево Меркла

Дерево Меркла – это способ хранения информации в виде хешей. Оно строится так: каждая транзакция хешируется – таким образом, формируются листья первой очереди. Затем хеши соседних листьев складывают(по 2) и снова получают хеш этой строки. Эту операцию проделывают до тех пор пока не остается 1 строка – это и есть корень дерева Меркла.

дерево Меркла
дерево Меркла

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

Так зачем же оно надо? Дело в том, что каждая транзакция, после попадания в блок, находится в “замороженном” состоянии. Она получает окончательное одобрение системой только после нескольких подтверждений. Это подтверждение блок транзакций получает при постройке следующих блоков, в которые, замороженная транзакция также вносится; к примеру, в биткоине, для признания транзакции вырлаты награды полностью легальной, нужно 100 подтверждений(последующих блоков), а на оплату биткоинами 6. Так вот, каждая проверка подтверждения требует усилий сети, а такая структура их экономит. Кроме экономии вычислительных мощностей, эта структура позволяет строить “легкие” клиенты – хранящие только корни дерева.

Данные подтверждения, как я понял, нужны для предотвращения двойных трат средств.

Сказ о сложности

Дело в том, что хеш, который мы видим – это представление в шестнадцатеричной форме; его можно перевести в десятеричную – и тогда это будет обычное число. Сложность это разница между максимальным значением хеша и текущим хешем. Строка с максимальной сложностью это, по сути, шестнадцатеричная строка, состоящая с самого старшого символа в этом формате и переведенная в десятичный. Допустимыми символами в шестнадцатеричной системе есть десять цифр(0 – 9) и шесть первых букв латинского алфавита(a – f), таким образом – старший символ f. Формула перерасчета выглядит так

где d – порядковый номер символа(0 – 15), n – порядковый номер символа в строке.

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

О майнинг-пулах

В начале, когда суммарные вычислительные мощности сети были малы – у каждого были шансы(они и сейчас есть) найти нонс–строку. Но когда крипта “выстрелила” и майнинг стал бизнесом, игроки стали обьеденять усилия для повышения своих шансов. Так умер соло-майнинг, потому как в кооперации можно договориться о разделении проверяемых значениях.

Кошелек и электронная подпись

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

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

По поводу баланса кошелька – система не хранит информацию о нем; он результат всех транзакций по адресу.

Что же такое криптовалюта?

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

Например, в сети Биткоин, вознаграждение за первые 210 тыс. блоков было по 50 монет; спустя каждые 210 тыс. оно делится на 2. Примерно, к 2033 году эмиссия новых монет прекратится, т.е. майнеры будут получать только комиссию. И-да, ответить – как же их увидеть? – первая транзакция в начале каждого тела блока.

Заключение

Здесь я кратко прошёлся по основным моментам крипты и всем, что с ней связано. В одной из будущих статей реализуем свою валюту; не в виде токена на существующем блокчейне, а создадим с ничего… В общем, to be continue…