Пользовательский виджет Wordpress Elementor с вложенными повторителями

Конечная цель - иметь виджет для Elementor в Wordpress, который может создавать несколько кнопок внутри вкладок. Итак, я хочу ретранслятор внутри ретранслятора.

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

Скриншот страницы Wordpress

Вот код:

<?php
namespace Elementor;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Elementor iatabs widget.
 *
 * Elementor widget that displays vertical or horizontal iatabs with different
 * pieces of content.
 *
 * @since 1.0.0
 */
class Widget_AltTabs extends Widget_Base {

    	/**
	 * Get widget name.
	 *
	 * Retrieve iatabs widget name.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget name.
	 */
	public function get_name() {
		return 'alttabs';
	}

	/**
	 * Get widget title.
	 *
	 * Retrieve tabs widget title.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget title.
	 */
	public function get_title() {
		return __( 'AltTabs', 'elementor' );
	}

	/**
	 * Get widget icon.
	 *
	 * Retrieve tabs widget icon.
	 *
	 * @since 1.0.0
	 * @access public
	 *
	 * @return string Widget icon.
	 */
	public function get_icon() {
		return 'eicon-tabs';
	}

protected function _register_controls() {

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

$this->add_control(
    'list',
    [
        'label' => __( 'Repeater List', 'elementor' ),
        'type' => Controls_Manager::REPEATER,
        'fields' => [
            [
                'name' => 'list_title',
                'label' => __( 'Title', 'elementor' ),
                'type' => Controls_Manager::TEXT,
                'default' => __( 'List Title' , 'elementor' ),
                'label_block' => true,
            ],
            [
                'name' => 'list_content',
                'label' => __( 'Content', 'elementor' ),
                'type' => Controls_Manager::WYSIWYG,
                'default' => __( 'List Content' , 'elementor' ),
                'show_label' => false,
            ],
            [
                'name' => 'list_buttons',
                'label' => __( 'List Buttons', 'elementor' ),
                'type' => Controls_Manager::REPEATER,
                'fields' => [
                    [
                        'name' => 'button_text',
                        'label' => __( 'Button Text', 'elementor' ),
                        'type' => Controls_Manager::TEXT,
                        'default' => __( 'Click' , 'elementor' ),
                        'label_block' => true,
                    ],
                ],
                'default' => [
                    [
                        'button_text' => __( 'Button #1', 'elementor' ),
                    ],
                    [
                        'button_text' => __( 'Button #2', 'elementor' ),
                    ],
                ],
            ],  
        ],
        'default' => [
            [
                'list_title' => __( 'Title #1', 'elementor' ),
                'list_content' => __( 'Item content. Click the edit button to change this text.', 'elementor' ),
            ],
            [
                'list_title' => __( 'Title #2', 'elementor' ),
                'list_content' => __( 'Item content. Click the edit button to change this text.', 'elementor' ),
            ],
        ],
        'title_field' => '{{{ list_title }}}',
    ]
);

$this->end_controls_section();

}

protected function render() {
    $settings = $this->get_settings_for_display();
    if ( $list ) {
        echo '<dl>';
        foreach (  $settings['list'] as $item ) {
            echo '<dt class="repeater-' . $item['_id'] . '">' . $item['list_title'] . '</dt>';
            echo '<dd>' . $item['list_content'] . '</dd>';
            foreach ($item['list_buttons'] as $button) {
                echo $button['button_text'];
            }
        }
        echo '</dl>';
    }
}

	/**
	 * Render tabs widget output in the editor.
	 *
	 * Written as a Backbone JavaScript template and used to generate the live preview.
	 *
	 * @since 1.0.0
	 * @access protected
	 */
    protected function _content_template() { ?>
        <# if ( settings.list ) { #>
            <dl>
            <# _.each( settings.list, function( item ) { #>
                <dt class="repeater-{{ item._id }}"> {{ item.list_title }} </dt>
                <dd> {{ item.list_content }} </dd>
                <dd> {{ item.list_buttons[0].button_text }} </dd>

                <# if ( item.list_buttons ) { #>
                    <dl>
                    <# _.each( item.list_buttons, function( i ) { #>
                        <dt class="repeater-{{ i._id }}"> </dt>
                        <dd> {{ i.button_text }} </dd>
                    <# }); #>
                    </dl>
                <# } #>

            <# }); #>
            </dl>
        <# } #>
        <?php
        }

    }
Plugin::instance()->widgets_manager->register_widget_type( new Widget_AltTabs ); ?>

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

Uncaught TypeError: невозможно прочитать свойство "each" из undefined в объекте. (editor.min.js? ver = 2.0.15: 2) в Function.each (load-scripts.php? c = 0 & load [] = подчеркивание, шорткод, utils, jquery-core, jquery-migrate, backbone, wp- util, wp-backbone, media-models, moxiejs, plupload, wp-plupload, jqu & load [] = ery-ui-core, jquery-ui-widget, jquery-ui-mouse, jquery-ui-sortable & ver = 4.9: 10) в n.getStyleControls (editor.min.js? ver = 2.0.15: 2) в editor.min.js? ver = 2.0.15: 2 в Function.m.each.m.forEach (load-scripts.php? c = 0 & load [] = подчеркивание, шорткод, utils, jquery-core, jquery-migrate, backbone, wp-util, wp-backbone, media-models, moxiejs, plupload, wp-plupload, jqu & load [] = ery-ui- core, jquery-ui-widget, jquery-ui-mouse, jquery-ui-sortable & ver = 4.9: 5) в e.Collection.each (load-scripts.php? c = 0 & load [] = подчеркивание, шорткод, utils, jquery -core, jquery-migrate, backbone, wp-util, wp-backbone, media-models, moxiejs, plupload, wp-plupload, jqu & load [] = ery-ui-core, jquery-ui-widget, jquery-ui-mouse , jquery-ui-sortable & ver = 4.9: 18) в Object. (editor.min.js? ver = 2.0.15: 2) в Function.each (load-scripts.php? c = 0 & load [] = подчеркивание, шорткод, utils, jquery-core, jquery-migrate, backbone, wp- util, wp-backbone, media-models, moxiejs, plupload, wp-plupload, jqu & load [] = ery-ui-core, jquery-ui-widget, jquery-ui-mouse, jquery-ui-sortable & ver = 4.9: 10) в n.getStyleControls (editor.min.js? ver = 2.0.15: 2) в n.renderStyles (editor.min.js? ver = 2.0.15: 2) ‹

Я новичок в написании виджетов / плагинов Elementor, поэтому я здесь в тупике. Буду признателен за любую помощь. Спасибо!


person Kris B    schedule 13.06.2018    source источник
comment
В сообщениях об ошибках указано, что _ в вашем вызове _.each не определено. Так что вам, вероятно, не хватает undersore.js или подобной библиотеки.   -  person Capricorn    schedule 13.06.2018
comment
Спасибо за комментарий! К сожалению, проблема не в этом, потому что, когда я удаляю внутренний повторитель, все работает нормально. Это что-то, когда я вставляю ретранслятор, что-то не так.   -  person Kris B    schedule 13.06.2018
comment
Тогда может быть проблема с областью видимости, что внутри внешнего цикла или какого-либо другого блока _ не определен. Однажды у меня были похожие проблемы с handlebarsjs   -  person Capricorn    schedule 14.06.2018
comment
В итоге я использовал SiteOrigin для создания виджета, поскольку Elementor может использовать виджеты SiteOrigin. Я знаком с этими виджетами, все прошло намного проще. Спасибо всем, кто на это посмотрел!   -  person Kris B    schedule 19.06.2018


Ответы (2)


Элементы управления повторителем не могут поддерживать вложенный повторитель

взгляните: https://github.com/pojome/elementor/issues/2955

person mademan12    schedule 04.07.2018
comment
Спасибо! Это прискорбно, но я рад, что, по крайней мере, знаю, что ничего не упускаю. Для всех, кому интересно, как я решил эту проблему, я фактически создал виджет SiteOrigin, который затем использовал в Elementor. Это не идеально, но мой босс и клиент остались очень довольны. - person Kris B; 09.07.2018

Мое решение

Сделайте два репитера и свяжите их ключами. Удачи

protected function _register_controls() {
    $this->start_controls_section(
        'section_categories',
        [
            'label' => __( 'Categories', 'elementor' ),
        ]
    );

    $repeater = new Repeater();

    $repeater->add_control(
        'category_slug',
        [
            'label'       => __( 'Category Slug', 'elementor' ),
            'type'        => Controls_Manager::TEXT,
            'default'     => __( 'category-name', 'elementor' ),
            'label_block' => true,
        ]
    );

    $repeater->add_control(
        'category_title',
        [
            'label'       => __( 'Category Title', 'elementor' ),
            'type'        => Controls_Manager::TEXT,
            'default'     => __( 'Category Title', 'elementor' ),
            'label_block' => true,
        ]
    );

    $this->add_control(
        'categories',
        [
            'label'       => __( 'Contacts', 'elementor' ),
            'type'        => Controls_Manager::REPEATER,
            'fields'      => $repeater->get_controls(),
            'title_field' => '{{{ category_title }}}',
        ]
    );

    $this->end_controls_section();

    $this->start_controls_section(
        'section_prices',
        [
            'label' => __( 'Prices', 'elementor' ),
        ]
    );

    $serviceRepeater = new Repeater();

    $serviceRepeater->add_control(
        'category_slug',
        [
            'label'       => __( 'Category Slug', 'elementor' ),
            'type'        => Controls_Manager::TEXT,
            'default'     => __( 'category-name', 'elementor' ),
            'label_block' => true,
        ]
    );

    $serviceRepeater->add_control(
        'service_title',
        [
            'label'       => __( 'Service Title', 'elementor' ),
            'type'        => Controls_Manager::TEXT,
            'default'     => __( 'Service Title', 'elementor' ),
            'label_block' => true,
        ]
    );

    $serviceRepeater->add_control(
        'service_price',
        [
            'label'       => __( 'Price', 'elementor' ),
            'type'        => Controls_Manager::TEXT,
            'default'     => __( '40,00', 'elementor' ),
            'label_block' => true,
        ]
    );

    $this->add_control(
        'services',
        [
            'label'       => __( 'Services', 'elementor' ),
            'type'        => Controls_Manager::REPEATER,
            'fields'      => $serviceRepeater->get_controls(),
            'title_field' => '{{{ service_title }}}',
        ]
    );

    $this->end_controls_section();
}

Добавить в рендер

foreach ($settings['categories'] as $category) {
    echo $category['category_title'];

    foreach($settings['services' as $service) {
        if ($category['category_slug'] === $service['category_slug'] {
            echo $category['service_title'];
        }
    }
}
person Solunski.D    schedule 29.01.2020