ID; $animation = get_post_meta($post_id, "_advanced_animation_props", true); $custom_css = get_post_meta($post_id, "_advanced_custom_css", true); $fe_script = require "build/frontend.asset.php"; wp_enqueue_script('frontend-script', plugin_dir_url(__FILE__) . 'build/frontend.js', $fe_script["dependencies"], $fe_script["version"], true); wp_localize_script('frontend-script', 'animationGlobal', array("props" => $animation)); //add inline style wp_register_style( 'wp-addon-custom-style', false ); wp_enqueue_style( 'wp-addon-custom-style' ); wp_add_inline_style('wp-addon-custom-style', $custom_css ); } add_action( 'wp_enqueue_scripts', 'wpaddons_fe_script' ); function wpaddons_post_meta() { $types = array("post", "page", "wp_block"); foreach($types as $type){ register_post_meta( $type, '_advanced_animation_props', array( 'single' => true, 'type' => 'string', 'show_in_rest' => true, 'auth_callback' => function() { return current_user_can( 'edit_posts' ); } ) ); register_post_meta( $type, '_advanced_custom_css', array( 'single' => true, 'type' => 'string', 'show_in_rest' => true, 'auth_callback' => function() { return current_user_can( 'edit_posts' ); } ) ); } } add_action( 'init', 'wpaddons_post_meta' ); function wpaddons_render_block($block_content, $block){ global $post; $post_id = $post->ID; $animation = get_post_meta($post_id, "_advanced_animation_props", true); $animation_meta = json_decode($animation); if(!isset($block['attrs'])){ return $block_content; } $attrs = $block['attrs']; $class = ""; // Add animation class if(isset($attrs["animationSettings"]) && isset($attrs["animationSettings"]["classAnimation"]) && count($attrs["animationSettings"]["classAnimation"]) && !empty($attrs["animationSettings"]["id"])){ $animationId = $attrs["animationSettings"]["id"]; $class = $class ." animation-". $animationId; } // Add custom CSS class if(isset($attrs["customCSSSettings"]) && !empty($attrs["customCSSSettings"]["customCSSClass"])){ $customCSSClass = $attrs["customCSSSettings"]["customCSSClass"]; $class = $class ." ". $customCSSClass; } if(!empty($class)){ $class = trim($class); $pos = strpos($block_content, $class); $class = 'class="'. $class . " "; if($pos === false){ $pos = strpos($block_content, "class"); if ($pos !== false) { $block_content = substr_replace($block_content, $class, $pos, 7); } } } return $block_content; } add_filter( 'render_block', 'wpaddons_render_block', 10, 2); /** * Reusable function to register animation controls for Elementor elements */ function wpaddons_register_animation_controls($element) { $element->start_controls_section( 'advanced_animation_section', [ 'label' => __('Advanced Animation', 'advanced-animation'), 'tab' => \Elementor\Controls_Manager::TAB_ADVANCED, ] ); // Enable Animation $element->add_control( 'advanced_animation_enable', [ 'label' => __('Enable Animation', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SWITCHER, 'default' => '', ] ); // Animation Settings (above keyframes) $element->add_control( 'advanced_animation_trigger_type', [ 'label' => __('Trigger Type', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 'onVisible' => __('On Visible', 'advanced-animation'), 'onScroll' => __('On Scroll', 'advanced-animation'), // 'onClick' => __('On Click', 'advanced-animation'), // 'onHover' => __('On Hover', 'advanced-animation'), ], 'default' => 'onVisible', 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->add_control( 'advanced_animation_trigger_once', [ 'label' => __('Run Once', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SWITCHER, 'default' => 'yes', 'condition' => [ 'advanced_animation_enable' => 'yes', 'advanced_animation_trigger_type' => 'onVisible', ], ] ); $element->add_control( 'advanced_animation_trigger_start', [ 'label' => __('Scroll Trigger Start', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 'start end' => __('Top of target at screen bottom', 'advanced-animation'), 'start start' => __('Top of target at screen top', 'advanced-animation'), 'start center' => __('Top of target at screen center', 'advanced-animation'), 'center center' => __('Center of target at screen center', 'advanced-animation'), 'end end' => __('Bottom of target at screen bottom', 'advanced-animation'), 'end start' => __('Bottom of target at screen top', 'advanced-animation'), 'end center' => __('Bottom of target at screen center', 'advanced-animation'), ], 'default' => 'start start', 'condition' => [ 'advanced_animation_enable' => 'yes', 'advanced_animation_trigger_type' => 'onScroll', ], ] ); $element->add_control( 'advanced_animation_trigger_end', [ 'label' => __('Scroll Trigger End', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 'end start' => __('Bottom of target at screen top', 'advanced-animation'), 'end end' => __('Bottom of target at screen bottom', 'advanced-animation'), 'end center' => __('Bottom of target at screen center', 'advanced-animation'), 'center center' => __('Center of target at screen center', 'advanced-animation'), 'start start' => __('Top of target at screen top', 'advanced-animation'), 'start end' => __('Top of target at screen bottom', 'advanced-animation'), 'start center' => __('Top of target at screen center', 'advanced-animation'), ], 'default' => 'end end', 'condition' => [ 'advanced_animation_enable' => 'yes', 'advanced_animation_trigger_type' => 'onScroll', ], ] ); $element->add_control( 'advanced_animation_custom_trigger', [ 'label' => __('Custom Scroll Trigger Element', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'placeholder' => __('#element-id or .class-name', 'advanced-animation'), 'description' => __('Enter a CSS selector (ID or class) for the element to use as scroll trigger reference. Leave empty to use the animated element itself.', 'advanced-animation'), 'condition' => [ 'advanced_animation_enable' => 'yes', 'advanced_animation_trigger_type' => 'onScroll', ], ] ); $element->add_control( 'advanced_animation_duration', [ 'label' => __('Duration (seconds)', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::NUMBER, 'default' => 0.5, 'step' => 0.1, 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->add_control( 'advanced_animation_delay', [ 'label' => __('Delay (seconds)', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::NUMBER, 'default' => 0, 'step' => 0.1, 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->add_control( 'advanced_animation_iteration_count', [ 'label' => __('Playing Iterations', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 1 => __('One time', 'advanced-animation'), 'infinite' => __('Infinite', 'advanced-animation'), ], 'default' => 1, 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->add_control( 'advanced_animation_direction', [ 'label' => __('Direction', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 'normal' => __('Normal', 'advanced-animation'), 'reverse' => __('Reverse', 'advanced-animation'), 'alternate' => __('Alternate', 'advanced-animation'), 'alternate-reverse' => __('Alternate Reverse', 'advanced-animation'), ], 'default' => 'normal', 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->add_control( 'advanced_animation_easing', [ 'label' => __('Easing', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'options' => [ 'linear' => __('Linear', 'advanced-animation'), 'easeInOut' => __('Ease In Out', 'advanced-animation'), 'easeIn' => __('Ease In', 'advanced-animation'), 'easeOut' => __('Ease Out', 'advanced-animation'), 'backInOut' => __('Back In Out', 'advanced-animation'), 'backIn' => __('Back In', 'advanced-animation'), 'backOut' => __('Back Out', 'advanced-animation'), 'circInOut' => __('Circ In Out', 'advanced-animation'), 'circIn' => __('Circ In', 'advanced-animation'), 'circOut' => __('Circ Out', 'advanced-animation'), // Add more as needed ], 'default' => 'easeOut', 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); // --- Dynamic Keyframe Controls --- $repeater = new \Elementor\Repeater(); $repeater->add_control( 'property', [ 'label' => __('Property', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => 'x', 'options' => [ 'x' => __('Translate X', 'advanced-animation'), 'y' => __('Translate Y', 'advanced-animation'), 'opacity' => __('Opacity', 'advanced-animation'), 'scale' => __('Scale', 'advanced-animation'), 'rotate' => __('Rotate', 'advanced-animation'), 'rotateX' => __('Rotate X', 'advanced-animation'), 'rotateY' => __('Rotate Y', 'advanced-animation'), 'transformPerspective' => __('Perspective', 'advanced-animation'), 'skewX' => __('Skew X', 'advanced-animation'), 'skewY' => __('Skew Y', 'advanced-animation'), 'scaleX' => __('Scale X', 'advanced-animation'), 'scaleY' => __('Scale Y', 'advanced-animation'), ], ] ); $repeater->add_control( 'start_value', [ 'label' => __('Start Value', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::NUMBER, 'default' => 0, 'step' => 0.01, ] ); $repeater->add_control( 'end_value', [ 'label' => __('End Value', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::NUMBER, 'default' => 1, 'step' => 0.01, ] ); $element->add_control( 'advanced_animation_keyframes', [ 'label' => __('Keyframe Properties', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::REPEATER, 'fields' => $repeater->get_controls(), 'default' => [ [ 'property' => 'opacity', 'start_value' => 0, 'end_value' => 1, ], ], 'title_field' => '{{{ property }}} : {{{ start_value }}} → {{{ end_value }}}', 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); // Custom Keyframes JSON $element->add_control( 'advanced_animation_custom_keyframes', [ 'label' => __('Custom Keyframes (JSON)', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::TEXTAREA, 'default' => '', 'description' => __('Add custom keyframe attributes as JSON. Example: { "backgroundColor": { "start": "#fff", "end": "#000" } }', 'advanced-animation'), 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); // Play Animation Button $element->add_control( 'advanced_animation_play_button', [ 'label' => __('Preview Animation', 'advanced-animation'), 'type' => \Elementor\Controls_Manager::BUTTON, 'text' => __('Play Animation', 'advanced-animation'), 'event' => 'advanced_animation:play', 'condition' => [ 'advanced_animation_enable' => 'yes', ], ] ); $element->end_controls_section(); } /** * Build animation attributes from Elementor settings */ function wpaddons_build_animation_attributes($settings) { $keyframes = []; // Build keyframes from repeater data if (!empty($settings['advanced_animation_keyframes'])) { foreach ($settings['advanced_animation_keyframes'] as $item) { if (!empty($item['property'])) { $keyframes[$item['property']] = [ 'start' => $item['start_value'], 'end' => $item['end_value'], ]; } } } // Merge custom keyframes JSON if present if (!empty($settings['advanced_animation_custom_keyframes'])) { $json = json_decode($settings['advanced_animation_custom_keyframes'], true); if (is_array($json)) { $keyframes = array_merge($keyframes, $json); } } return [ 'triggerType' => $settings['advanced_animation_trigger_type'], 'triggerOnce' => $settings['advanced_animation_trigger_once'], 'triggerStart' => $settings['advanced_animation_trigger_start'], 'triggerEnd' => $settings['advanced_animation_trigger_end'], 'customTrigger' => !empty($settings['advanced_animation_custom_trigger']) ? $settings['advanced_animation_custom_trigger'] : '', 'duration' => $settings['advanced_animation_duration'], 'delay' => $settings['advanced_animation_delay'], 'iterationCount' => $settings['advanced_animation_iteration_count'], 'direction' => $settings['advanced_animation_direction'], 'easing' => $settings['advanced_animation_easing'], 'keyframes' => $keyframes, ]; } // Elementor: Register Animation Controls for Widgets add_action('elementor/element/common/_section_style/after_section_end', function($element, $args) { wpaddons_register_animation_controls($element); }, 10, 2); // Add animation attributes to Elementor widget wrapper add_filter('elementor/frontend/widget/should_render', function($should_render, $widget) { $settings = $widget->get_settings_for_display(); if (!empty($settings['advanced_animation_enable'])) { $animation_settings = wpaddons_build_animation_attributes($settings); $widget->add_render_attribute('_wrapper', [ 'data-advanced-animation' => 'yes', 'data-animation-settings' => htmlspecialchars(json_encode($animation_settings), ENT_QUOTES, 'UTF-8'), ]); } return $should_render; }, 10, 2); // Elementor: Register Animation Controls for Containers add_action('elementor/element/container/section_layout/after_section_end', function($element, $args) { wpaddons_register_animation_controls($element); }, 10, 2); // Add animation attributes to Elementor container wrapper add_filter('elementor/frontend/container/should_render', function($should_render, $container) { $settings = $container->get_settings_for_display(); if (!empty($settings['advanced_animation_enable'])) { $animation_settings = wpaddons_build_animation_attributes($settings); $container->add_render_attribute('_wrapper', [ 'data-advanced-animation' => 'yes', 'data-animation-settings' => htmlspecialchars(json_encode($animation_settings), ENT_QUOTES, 'UTF-8'), ]); } return $should_render; }, 10, 2); /** * Enqueue Elementor editor animation preview scripts */ function wpaddons_enqueue_elementor_editor_scripts() { $elementor_editor_asset = include(plugin_dir_path(__FILE__) . 'build/elementor-editor.asset.php'); wp_enqueue_script( 'wpaddons-elementor-editor', plugins_url('build/elementor-editor.js', __FILE__), array('jquery'), $elementor_editor_asset['version'], true ); } add_action('elementor/editor/after_enqueue_scripts', 'wpaddons_enqueue_elementor_editor_scripts'); //include custom css file with the plugin or theme add_action('elementor/init', function () { if (defined('ELEMENTOR_VERSION')) { require_once plugin_dir_path(__FILE__) . 'elementor-custom-css.php'; } });