elementor / elementor

The most advanced frontend drag & drop page builder. Create high-end, pixel perfect websites at record speeds. Any theme, any page, any design.
https://elementor.com/
GNU General Public License v3.0
6.57k stars 1.42k forks source link

Dynamic acf content not translated in $settings when using custom posts skin #9491

Open creattic opened 4 years ago

creattic commented 4 years ago

Hey there guys,

just registered a custom build skin for the posts element, added some static and dynamic text fields and parsed them due to rendering process. For any reason they are not translated.

I handled the fields as I did before in a custom made widget where I was able to render the fields without any problems.

In case of the custom skin which extends Skin_Base the get_settings_for_display() just returns an array with all the registered fields, the static ones containing what was typed in and the dynamic ones are empty. Having a look at the $settings array I found the [dynamic] which contains the correct information the [elementor..... ] shortcodes which are used to translate the acf fields to readable content.

Broken down to the DynamicTags manager the parse_tag_text() just returns empty results to the settings

Any suggestions what is wrong?

bainternet commented 4 years ago

Thanks for reporting, Please follow guidelines for opening a new issue report, so we can help you better. This report is missing key information:

Without it, we can't replicate or help.

creattic commented 4 years ago

Hey there,

as I mentioned, the prerequisites and steps to replicate are registering a a custom skin for the elementor pro posts widget.

namespace ElementorPro\Modules\Posts\Skins;

use Elementor\Controls_Manager;
use Elementor\Group_Control_Css_Filter;
use Elementor\Group_Control_Image_Size;
use Elementor\Group_Control_Typography;
use Elementor\Scheme_Color;
use Elementor\Scheme_Typography;
use Elementor\Widget_Base;

class Skin_Escort_Cards extends Skin_Base {

    protected function _register_controls_actions() {
        parent::_register_controls_actions();

        add_action( 'elementor/element/posts/cards_section_design_image/before_section_end', [ $this, 'register_additional_design_image_controls' ] );
        add_action( 'elementor/element/posts/section_query/before_section_start', [ $this, 'register_content_controls' ] );
        #add_action( 'elementor/element/posts/cards_section_design_content/after_section_end', [ $this, 'register_design_var_controls' ] );
    }

    public function get_id() {
        return 'escort-cards';
    }
    public function get_title() {
        return __( 'Escort Cards', 'elementor-pro' );
    }

    public function start_controls_tab( $id, $args ) {
        $args['condition']['_skin'] = $this->get_id();
        $this->parent->start_controls_tab( $this->get_control_id( $id ), $args );
    }

    public function end_controls_tab() {
        $this->parent->end_controls_tab();
    }

    public function start_controls_tabs( $id ) {
        $args['condition']['_skin'] = $this->get_id();
        $this->parent->start_controls_tabs( $this->get_control_id( $id ) );
    }

    public function end_controls_tabs() {
        $this->parent->end_controls_tabs();
    }

    public function register_controls( Widget_Base $widget ) {
        $this->parent = $widget;

        $this->register_columns_controls();
        $this->register_post_count_control();
        $this->register_thumbnail_controls();
        $this->register_title_controls();
    }

    public function register_design_controls() {
        $this->register_design_layout_controls();
        $this->register_design_card_controls();
        $this->register_design_image_controls();
        $this->register_design_content_controls();
    }

    protected function register_thumbnail_controls() {
        parent::register_thumbnail_controls();
        $this->remove_responsive_control( 'image_width' );
        $this->update_control(
            'thumbnail',
            [
                'label' => __( 'Show Image', 'elementor-pro' ),
                'options' => [
                    'top' => __( 'Yes', 'elementor-pro' ),
                    'none' => __( 'No', 'elementor-pro' ),
                ],
                'render_type' => 'template',
            ]
        );
    }

    public function register_additional_design_image_controls() {
        $this->update_control(
            'image_spacing',
            [
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__text' => 'margin-top: {{SIZE}}{{UNIT}}',
                ],
                'condition' => [
                    $this->get_control_id( 'thumbnail!' ) => 'none',
                ],
            ]
        );

        $this->remove_control( 'img_border_radius' );
    }

    public function register_design_card_controls() {
        $this->start_controls_section(
            'section_design_card',
            [
                'label' => __( 'Card', 'elementor-pro' ),
                'tab' => Controls_Manager::TAB_STYLE,
            ]
        );

        $this->add_control(
            'card_bg_color',
            [
                'label' => __( 'Background Color', 'elementor-pro' ),
                'type' => Controls_Manager::COLOR,
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card' => 'background-color: {{VALUE}}',
                ],
            ]
        );

        $this->add_control(
            'card_border_color',
            [
                'label' => __( 'Border Color', 'elementor-pro' ),
                'type' => Controls_Manager::COLOR,
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card' => 'border-color: {{VALUE}}',
                ],
            ]
        );

        $this->add_control(
            'card_border_width',
            [
                'label' => __( 'Border Width', 'elementor-pro' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ 'px' ],
                'range' => [
                    'px' => [
                        'min' => 0,
                        'max' => 15,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card' => 'border-width: {{SIZE}}{{UNIT}}',
                ],
            ]
        );

        $this->add_control(
            'card_border_radius',
            [
                'label' => __( 'Border Radius', 'elementor-pro' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ 'px', '%' ],
                'range' => [
                    'px' => [
                        'min' => 0,
                        'max' => 200,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card' => 'border-radius: {{SIZE}}{{UNIT}}',
                ],
            ]
        );

        $this->add_control(
            'card_padding',
            [
                'label' => __( 'Horizontal Padding', 'elementor-pro' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ 'px' ],
                'range' => [
                    'px' => [
                        'min' => 0,
                        'max' => 50,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__text' => 'padding: 0 {{SIZE}}{{UNIT}}',
                    '{{WRAPPER}} .elementor-post__meta-data' => 'padding: 10px {{SIZE}}{{UNIT}}',
                    '{{WRAPPER}} .elementor-post__avatar' => 'padding-right: {{SIZE}}{{UNIT}}; padding-left: {{SIZE}}{{UNIT}}',
                ],
            ]
        );

        $this->add_control(
            'card_vertical_padding',
            [
                'label' => __( 'Vertical Padding', 'elementor-pro' ),
                'type' => Controls_Manager::SLIDER,
                'size_units' => [ 'px' ],
                'range' => [
                    'px' => [
                        'min' => 0,
                        'max' => 50,
                    ],
                ],
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card' => 'padding-top: {{SIZE}}{{UNIT}}; padding-bottom: {{SIZE}}{{UNIT}}',
                ],
            ]
        );

        $this->add_control(
            'box_shadow_box_shadow_type', // The name of this control is like that, for future extensibility to group_control box shadow.
            [
                'label' => __( 'Box Shadow', 'elementor-pro' ),
                'type' => Controls_Manager::SWITCHER,
                'prefix_class' => 'elementor-card-shadow-',
                'default' => 'yes',
            ]
        );

        $this->add_control(
            'hover_effect',
            [
                'label' => __( 'Hover Effect', 'elementor-pro' ),
                'type' => Controls_Manager::SELECT,
                'label_block' => false,
                'options' => [
                    'none' => __( 'None', 'elementor-pro' ),
                    'gradient' => __( 'Gradient', 'elementor-pro' ),
                    //'zoom-in' => __( 'Zoom In', 'elementor-pro' ),
                    //'zoom-out' => __( 'Zoom Out', 'elementor-pro' ),
                ],
                'default' => 'gradient',
                'separator' => 'before',
                'prefix_class' => 'elementor-posts__hover-',
            ]
        );

        $this->add_control(
            'meta_border_color',
            [
                'label' => __( 'Meta Border Color', 'elementor-pro' ),
                'type' => Controls_Manager::COLOR,
                'separator' => 'before',
                'selectors' => [
                    '{{WRAPPER}} .elementor-post__card .elementor-post__meta-data' => 'border-top-color: {{VALUE}}',
                ],
                'condition' => [
                    $this->get_control_id( 'meta_data!' ) => [],
                ],
            ]
        );

        $this->end_controls_section();
    }

    public function register_content_controls() {
        $this->start_controls_section(
            'section_content',
            [
                'label' => __( 'Content', 'elementor-escort' ),
            ]
        );

        for($i=1;$i<=7;$i++){

            $this->add_control(
                'var'.$i.'_title',
                [
                    'label' => __( 'Variable '.$i.' Title', 'elementor-escort' ),
                    'type' => Controls_Manager::TEXT,
                    'dynamic' => [
                        'active' => false,
                    ],
                    'default' => __( '', 'elementor-escort' ),
                ]
            );

            $this->add_control(
                'var'.$i,
                [
                    'label' => __( 'Variable '.$i, 'elementor-escort' ),
                    'type' => Controls_Manager::TEXT,
                    'dynamic' => [
                        'active' => true,
                    ],
                    'default' => __( '', 'elementor-escort' ),
                ]
            );
        }

        $this->end_controls_section();
    }

    public function register_design_var_controls(){
        for ($i=1 ; $i<=7 ; $i++){
            $this->start_controls_section(
                'section_var'.$i.'_style',
                [
                    'label'                 => __( 'Variable '.$i, 'powerpack' ),
                    'tab'                   => Controls_Manager::TAB_STYLE,
                ]
            );

            $this->add_control(
                'var'.$i.'_text_color',
                [
                    'label'                 => __( 'Text Color', 'powerpack' ),
                    'type'                  => Controls_Manager::COLOR,
                    'default'               => '',
                    'selectors'             => [
                        '{{WRAPPER}} .escort-var-title-var'.$i => 'color: {{VALUE}};',
                    ],
                ]
            );

            $this->add_group_control(
                Group_Control_Typography::get_type(),
                [
                    'name'                  => 'escort_cards_var'.$i.'_typography',
                    'label'                 => __( 'Typography', 'powerpack' ),
                    'selector'              => '{{WRAPPER}} .escort-var-title-var'.$i,
                ]
            );

            $this->end_controls_section();

        }
    }

    protected function register_design_content_controls() {
        parent::register_design_content_controls();
        $this->remove_control( 'meta_spacing' );
    }

    protected function get_taxonomies() {
        $taxonomies = get_taxonomies( [ 'show_in_nav_menus' => true ], 'objects' );

        $options = [ '' => '' ];

        foreach ( $taxonomies as $taxonomy ) {
            $options[ $taxonomy->name ] = $taxonomy->label;
        }

        return $options;
    }

    protected function render_thumbnail($type='') {
        if ( 'none' === $this->get_instance_value( 'thumbnail' ) ) {
            return;
        }

        $settings = $this->parent->get_settings();
        $setting_key = $this->get_control_id( 'thumbnail_size' );

        $settings[ $setting_key ] = [
            'id' => get_post_thumbnail_id(),
        ];
        $thumbnail_html = Group_Control_Image_Size::get_attachment_image_html( $settings, $setting_key );

        if ( empty( $thumbnail_html ) ) {
            return;
        }
        ?>
        <a class="elementor-post__thumbnail__link" href="<?php echo get_permalink(); ?>">
            <div class="elementor-post__thumbnail"><?php echo $thumbnail_html; ?></div>
        </a>
        <?php
    }

    protected function render_title() {
        if ( ! $this->get_instance_value( 'show_title' ) ) {
            return;
        }

        $tag = $this->get_instance_value( 'title_tag' );
        ?>
        <<?php echo $tag; ?> class="elementor-post__title">
        <a href="<?php echo $this->current_permalink; ?>">
            <?php the_title(); ?> <span>(<?php echo get_field('escort_age'); ?>)</span>
        </a>
        </<?php echo $tag; ?>>
        <span><?php echo get_field('escort_location'); ?></span>
        <?php
    }

    protected function render_post_header() {
        ?>
        <article <?php post_class( [ 'elementor-post elementor-grid-item escort-grid-element' ] ); ?>>
        <?php
    }

    protected function render_post_footer() {
        ?>
        </article>
        <?php
    }

    protected function render_text_header() {
        ?>
        <div class="elementor-post__text">
        <?php
    }

    protected function render_text_footer() {
        ?>
        </div>
        <?php
    }

    protected function render_default_card_header() {
        ?>
        <div class="escort_base">
        <?php
    }

    protected function render_default_card_footer() {
        ?>
        </div>
        <?php
    }

    protected function render_hover_card_header() {
        ?>
        <div class="escort_infos">
            <div class="image">
        <?php
    }

    protected function render_hover_card_content() {
        $settings = $this->get_settings_for_display();
        $settings = $this->translateDynamicField($settings);
    ?>
        </div>
        <div class="base">
            <span class="name"><?php the_title(); ?></span>
        </div>
        <div class="content">
    <?php
            for($i=1; $i<=7; $i++){
                if($settings['escort_cards_var'.$i] == '') {
                    continue;
                }

                ${'var'.$i} = $settings['escort_cards_var'.$i];
                ${'var'.$i.'_title'} = $settings['escort_cards_var'.$i.'_title'];
        ?>
                <div class="escort-details">
            <?php
                if(${'var'.$i.'_title'} != ''){
            ?>
                        <span><?php echo ${'var'.$i.'_title'}; ?></span>
            <?php
                }
            ?>
                    <span><?php echo ${'var'.$i}; ?></span>
                </div>
        <?php
            }
         ?>
            <a href="<?php echo $this->current_permalink; ?>" class="elementor-button-link elementor-button elementor-size-xs" role="button">
                <span class="elementor-button-content-wrapper">
                    <span class="elementor-button-text elementor-inline-editing" data-elementor-setting-key="text" data-elementor-inline-editing-toolbar="none">zum Profil​</span>
                </span>
            </a>
        </div>
        <?php
    }

    private function translateDynamicField($settings){
        foreach ($settings['__dynamic__'] as $key => $val){
            preg_match( '/settings="(.*?(?="]))/', $val, $tag_settings_match );
            $keyStr = json_decode( urldecode( $tag_settings_match[1] ), true );
            $fieldname = substr($keyStr['key'], strpos($keyStr['key'], ":") + 1);
            $settings[$key] = (($keyStr['before'])?$keyStr['before']:'').get_field($fieldname, get_the_ID()).(($keyStr['after'])?$keyStr['after']:'');
        }

        return $settings;
    }

    protected function render_hover_card_footer() {
        ?>
        </div>
        <?php
    }

    private function get_settings_for_display() {
        return $this->parent->get_settings_for_display();
    }

    protected function render_post() {
        $this->render_post_header();
        $this->render_default_card_header();
        $this->render_thumbnail();
        $this->render_text_header();
        $this->render_title();
        $this->render_text_footer();
        $this->render_default_card_footer();
        $this->render_hover_card_header();
        $this->render_thumbnail();
        $this->render_hover_card_content();
        $this->render_hover_card_footer();
        $this->render_post_footer();
    }

}
add_action( 'elementor/widget/posts/skins_init', function( $widget ) {
    $widget->add_skin( new Skin_Escort_Cards( $widget ) );
} );

If I wouldn't use the translateDynamicField function I- couldn't use the dynamic vars. Any suggestions why the dynamic contains the correct information but isn't translated by elementors core functionality?

Isolation Problem Problem just occures at the custom posts skins, there is a small widget which I created on that project, it is also using the dynamic functionality and it works well.

System information WP 5.2.4 Elementor Pro 2.7.3 PHP 7.2.24 What else do you need?

Best regards Dominik

davidxoma commented 3 years ago

Hello guys. I use your code "creattic" in my elementor project and of course I have the same problem. Did you solve this issue? I really need some skin code with controls. Really need. Thanks

kimil14 commented 2 years ago

Hello, It is necessary to pass the ID variable of the current post in the rendering and not of the page.

Example:

protected function render_icon() {
        $settings = $this->parent->get_settings_for_display();

        $settings = $this->translateDynamicField($settings, get_the_ID()); //transformation des champs ACF au post de posts
}
private function translateDynamicField($settings, $id){
        foreach ($settings as $key => $val){
            //SIMPLE FIELD
            if($key === "__dynamic__"){
                foreach($val as $k => $v){
                    preg_match( '/settings="(.*?(?="]))/', $v, $tag_settings_match );
                    $keyStr = json_decode( urldecode( $tag_settings_match[1] ), true );
                    $fieldname = substr($keyStr['key'], strpos($keyStr['key'], ":") + 1);
                    $settings[$k] = (($keyStr['before'])?$keyStr['before']:'').get_field($fieldname, $id).(($keyStr['after'])?$keyStr['after']:'');     
                    continue;
                }
            }
            //GROUP FIELDS
            foreach ($val as $key2 => $val2){           
                foreach($val2 as $key3 => $val3){
                    if($key3 === "__dynamic__"){
                        foreach($val3 as $k => $v){     
                            preg_match( '/settings="(.*?(?="]))/', $v, $tag_settings_match );
                            $keyStr = json_decode( urldecode( $tag_settings_match[1] ), true );
                            $fieldname = substr($keyStr['key'], strpos($keyStr['key'], ":") + 1);                       
                            $settings[$key][$key2][$k] = ((($keyStr['before'])?$keyStr['before']:'').get_field($fieldname, $id).(($keyStr['after'])?$keyStr['after']:''));
                            continue;
                        }
                    }
                }                       
            }
        }

        return $settings;
    }