elementor
/
modules
/
atomic-widgets
/
elements
/
atomic-background-video
/
atomic-background-video.php
atomic-background-video.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at modules/atomic-widgets/elements/atomic-background-video/atomic-background-video.php
| 1 | <?php |
| 2 | |
| 3 | namespace Elementor\Modules\AtomicWidgets\Elements\Atomic_Background_Video; |
| 4 | |
| 5 | use Elementor\Modules\AtomicWidgets\ChildrenDependencies\Child_Dependency; |
| 6 | use Elementor\Modules\AtomicWidgets\Controls\Section; |
| 7 | use Elementor\Modules\AtomicWidgets\Controls\Types\Html_Tag_Control; |
| 8 | use Elementor\Modules\AtomicWidgets\Controls\Types\Number_Control; |
| 9 | use Elementor\Modules\AtomicWidgets\Controls\Types\Switch_Control; |
| 10 | use Elementor\Modules\AtomicWidgets\Controls\Types\Text_Control; |
| 11 | use Elementor\Modules\AtomicWidgets\Controls\Types\Toggle_Control; |
| 12 | use Elementor\Modules\AtomicWidgets\Controls\Types\Video_Control; |
| 13 | use Elementor\Modules\AtomicWidgets\DynamicTags\Dynamic_Prop_Type; |
| 14 | use Elementor\Modules\AtomicWidgets\Elements\Atomic_Background_Video\Atomic_Background_Video_Content\Atomic_Background_Video_Content; |
| 15 | use Elementor\Modules\AtomicWidgets\Elements\Atomic_Background_Video\Atomic_Background_Video_Controls\Atomic_Background_Video_Controls; |
| 16 | use Elementor\Modules\AtomicWidgets\Elements\Atomic_Background_Video\Atomic_Background_Video_Pause\Atomic_Background_Video_Pause; |
| 17 | use Elementor\Modules\AtomicWidgets\Elements\Atomic_Background_Video\Atomic_Background_Video_Play\Atomic_Background_Video_Play; |
| 18 | use Elementor\Modules\AtomicWidgets\Elements\Base\Atomic_Element_Base; |
| 19 | use Elementor\Modules\AtomicWidgets\Elements\Base\Element_Builder; |
| 20 | use Elementor\Modules\AtomicWidgets\Elements\Base\Has_Element_Template; |
| 21 | use Elementor\Modules\AtomicWidgets\Elements\Base\Html_Tag_Computer; |
| 22 | use Elementor\Modules\AtomicWidgets\Elements\Loader\Frontend_Assets_Loader; |
| 23 | use Elementor\Modules\AtomicWidgets\PropDependencies\Manager as Dependency_Manager; |
| 24 | use Elementor\Modules\AtomicWidgets\PropTypes\Attributes_Prop_Type; |
| 25 | use Elementor\Modules\AtomicWidgets\PropTypes\Classes_Prop_Type; |
| 26 | use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\Boolean_Prop_Type; |
| 27 | use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\Number_Prop_Type; |
| 28 | use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\String_Prop_Type; |
| 29 | use Elementor\Modules\AtomicWidgets\PropTypes\Size_Prop_Type; |
| 30 | use Elementor\Modules\AtomicWidgets\PropTypes\Video_Src_Prop_Type; |
| 31 | use Elementor\Modules\AtomicWidgets\Styles\Style_Definition; |
| 32 | use Elementor\Modules\AtomicWidgets\Styles\Style_Variant; |
| 33 | use Elementor\Modules\AtomicWidgets\Utils\Element_Position; |
| 34 | use Elementor\Modules\Components\PropTypes\Overridable_Prop_Type; |
| 35 | use Elementor\Plugin; |
| 36 | use Elementor\Utils; |
| 37 | |
| 38 | if ( ! defined( 'ABSPATH' ) ) { |
| 39 | exit; |
| 40 | } |
| 41 | |
| 42 | class Atomic_Background_Video extends Atomic_Element_Base { |
| 43 | use Has_Element_Template; |
| 44 | |
| 45 | const BASE_STYLE_KEY = 'base'; |
| 46 | const ELEMENT_TYPE_CONTENT = 'e-background-video-content'; |
| 47 | const ELEMENT_TYPE_CONTROLS = 'e-background-video-controls'; |
| 48 | const ELEMENT_TYPE_PLAY = 'e-background-video-play'; |
| 49 | const ELEMENT_TYPE_PAUSE = 'e-background-video-pause'; |
| 50 | |
| 51 | public static $widget_description = 'Create a section with a looping video background and content layered on top. REQUIRED direct children: e-background-video-content (content area) and e-background-video-controls (play/pause controls). The controls container MUST include e-background-video-play and e-background-video-pause, each with a required e-paragraph child for the button label.'; |
| 52 | |
| 53 | public function __construct( $data = [], $args = null ) { |
| 54 | parent::__construct( $data, $args ); |
| 55 | $this->meta( 'is_container', true ); |
| 56 | } |
| 57 | |
| 58 | public static function get_type() { |
| 59 | return 'e-background-video'; |
| 60 | } |
| 61 | |
| 62 | public static function get_element_type(): string { |
| 63 | return 'e-background-video'; |
| 64 | } |
| 65 | |
| 66 | public function get_title() { |
| 67 | return esc_html__( 'Background Video', 'elementor' ); |
| 68 | } |
| 69 | |
| 70 | public function get_keywords() { |
| 71 | return [ 'ato', 'atom', 'atoms', 'atomic', 'video', 'background', 'bg', 'media', 'autoplay', 'hero', 'film', 'mp4' ]; |
| 72 | } |
| 73 | |
| 74 | public function get_icon() { |
| 75 | return 'eicon-background-video'; |
| 76 | } |
| 77 | |
| 78 | public static function get_computed_html_tag( array $settings ): string { |
| 79 | return Html_Tag_Computer::compute( $settings, 'div' ); |
| 80 | } |
| 81 | |
| 82 | protected static function define_props_schema(): array { |
| 83 | // The States control is design-time only and directly tied to the controls. A prop dependency |
| 84 | // describes when the control is *shown* (the editor hides it when the dependency is not met), |
| 85 | // so show States only while Show Controls is on; the value is preserved when hidden (no reset). |
| 86 | $state_dependencies = Dependency_Manager::make() |
| 87 | ->where( [ |
| 88 | 'operator' => 'eq', |
| 89 | 'path' => [ 'show_controls' ], |
| 90 | 'value' => true, |
| 91 | 'effect' => 'hide', |
| 92 | ] ) |
| 93 | ->get(); |
| 94 | |
| 95 | return [ |
| 96 | 'classes' => Classes_Prop_Type::make()->default( [] ), |
| 97 | 'tag' => String_Prop_Type::make() |
| 98 | ->enum( [ 'div', 'header', 'section', 'article', 'aside', 'footer' ] ) |
| 99 | ->default( 'div' ) |
| 100 | ->description( 'The HTML tag for the background video container. Could be div, header, section, article, aside, or footer.' ), |
| 101 | 'source' => Video_Src_Prop_Type::make()->alias( 'video', 'src' ), |
| 102 | 'start_time' => Number_Prop_Type::make() |
| 103 | ->default( null ) |
| 104 | ->meta( Dynamic_Prop_Type::ignore() ) |
| 105 | ->meta( 'suffix', 'SEC' ), |
| 106 | 'end_time' => Number_Prop_Type::make() |
| 107 | ->default( null ) |
| 108 | ->meta( 'suffix', 'SEC' ) |
| 109 | ->meta( Dynamic_Prop_Type::ignore() ), |
| 110 | 'autoplay' => Boolean_Prop_Type::make()->default( true ), |
| 111 | 'mute' => Boolean_Prop_Type::make()->default( true ), |
| 112 | 'loop' => Boolean_Prop_Type::make()->default( true ), |
| 113 | 'show_controls' => Boolean_Prop_Type::make()->default( true ), |
| 114 | 'state' => String_Prop_Type::make() |
| 115 | ->enum( [ 'playing', 'paused' ] ) |
| 116 | ->default( 'playing' ) |
| 117 | ->set_dependencies( $state_dependencies ) |
| 118 | ->meta( Overridable_Prop_Type::ignore() ), |
| 119 | 'attributes' => Attributes_Prop_Type::make()->meta( Overridable_Prop_Type::ignore() ), |
| 120 | ]; |
| 121 | } |
| 122 | |
| 123 | protected function define_atomic_controls(): array { |
| 124 | return [ |
| 125 | Section::make() |
| 126 | ->set_label( __( 'Content', 'elementor' ) ) |
| 127 | ->set_id( 'content' ) |
| 128 | ->set_items( [ |
| 129 | Video_Control::bind_to( 'source' ) |
| 130 | ->set_label( esc_html__( 'Video', 'elementor' ) ), |
| 131 | Number_Control::bind_to( 'start_time' ) |
| 132 | ->set_label( esc_html__( 'Start Time', 'elementor' ) ) |
| 133 | ->set_min( 0 ) |
| 134 | ->set_max( 10000 ), |
| 135 | Number_Control::bind_to( 'end_time' ) |
| 136 | ->set_label( esc_html__( 'End Time', 'elementor' ) ) |
| 137 | ->set_min( 0 ) |
| 138 | ->set_max( 10000 ), |
| 139 | Switch_Control::bind_to( 'autoplay' ) |
| 140 | ->set_label( esc_html__( 'Autoplay', 'elementor' ) ), |
| 141 | Switch_Control::bind_to( 'mute' ) |
| 142 | ->set_label( esc_html__( 'Mute', 'elementor' ) ), |
| 143 | Switch_Control::bind_to( 'loop' ) |
| 144 | ->set_label( esc_html__( 'Loop', 'elementor' ) ), |
| 145 | Switch_Control::bind_to( 'show_controls' ) |
| 146 | ->set_label( esc_html__( 'Show Controls', 'elementor' ) ), |
| 147 | Toggle_Control::bind_to( 'state' ) |
| 148 | ->set_label( esc_html__( 'States', 'elementor' ) ) |
| 149 | ->add_options( [ |
| 150 | 'playing' => [ 'title' => esc_html__( 'Play', 'elementor' ) ], |
| 151 | 'paused' => [ 'title' => esc_html__( 'Pause', 'elementor' ) ], |
| 152 | ] ) |
| 153 | ->set_exclusive( true ) |
| 154 | ->set_allow_empty( true ) |
| 155 | ->set_convert_options( true ) |
| 156 | ->set_size( 'tiny' ) |
| 157 | ->set_full_width( true ), |
| 158 | ] ), |
| 159 | Section::make() |
| 160 | ->set_label( __( 'Settings', 'elementor' ) ) |
| 161 | ->set_id( 'settings' ) |
| 162 | ->set_items( [ |
| 163 | Html_Tag_Control::bind_to( 'tag' ) |
| 164 | ->set_options( [ |
| 165 | [ |
| 166 | 'value' => 'div', |
| 167 | 'label' => 'Div', |
| 168 | ], |
| 169 | [ |
| 170 | 'value' => 'header', |
| 171 | 'label' => 'Header', |
| 172 | ], |
| 173 | [ |
| 174 | 'value' => 'section', |
| 175 | 'label' => 'Section', |
| 176 | ], |
| 177 | [ |
| 178 | 'value' => 'article', |
| 179 | 'label' => 'Article', |
| 180 | ], |
| 181 | [ |
| 182 | 'value' => 'aside', |
| 183 | 'label' => 'Aside', |
| 184 | ], |
| 185 | [ |
| 186 | 'value' => 'footer', |
| 187 | 'label' => 'Footer', |
| 188 | ], |
| 189 | ] ) |
| 190 | ->set_label( esc_html__( 'HTML Tag', 'elementor' ) ), |
| 191 | Text_Control::bind_to( '_cssid' ) |
| 192 | ->set_label( __( 'ID', 'elementor' ) ) |
| 193 | ->set_meta( $this->get_css_id_control_meta() ), |
| 194 | ] ), |
| 195 | ]; |
| 196 | } |
| 197 | |
| 198 | protected function define_base_styles(): array { |
| 199 | return [ |
| 200 | static::BASE_STYLE_KEY => Style_Definition::make() |
| 201 | ->add_variant( |
| 202 | Style_Variant::make() |
| 203 | ->add_props( [ |
| 204 | 'display' => String_Prop_Type::generate( 'flex' ), |
| 205 | 'flex-direction' => String_Prop_Type::generate( 'column' ), |
| 206 | 'position' => String_Prop_Type::generate( 'relative' ), |
| 207 | 'overflow' => String_Prop_Type::generate( 'hidden' ), |
| 208 | // Match Flexbox/container default padding so the empty-state outline and |
| 209 | // stacking gaps match other layout elements. Absolute video still covers |
| 210 | // the full padding box (abspos containing block = padding edge). |
| 211 | 'padding' => Size_Prop_Type::generate( [ |
| 212 | 'size' => 10, |
| 213 | 'unit' => 'px', |
| 214 | ] ), |
| 215 | 'width' => Size_Prop_Type::generate( [ |
| 216 | 'size' => 100, |
| 217 | 'unit' => '%', |
| 218 | ] ), |
| 219 | ] ) |
| 220 | ), |
| 221 | ]; |
| 222 | } |
| 223 | |
| 224 | protected function define_default_children() { |
| 225 | $content = Atomic_Background_Video_Content::generate() |
| 226 | ->meta( [ 'required' => true ] ) |
| 227 | ->editor_settings( [ |
| 228 | 'title' => esc_html__( 'Content Area', 'elementor' ), |
| 229 | ] ) |
| 230 | ->build(); |
| 231 | |
| 232 | $controls = Atomic_Background_Video_Controls::generate() |
| 233 | ->meta( [ 'required' => true ] ) |
| 234 | ->editor_settings( [ |
| 235 | 'title' => esc_html__( 'Controls', 'elementor' ), |
| 236 | ] ) |
| 237 | ->children( [ |
| 238 | Atomic_Background_Video_Play::build_default_element( true ), |
| 239 | Atomic_Background_Video_Pause::build_default_element( true ), |
| 240 | ] ) |
| 241 | ->build(); |
| 242 | |
| 243 | return [ |
| 244 | $content, |
| 245 | $controls, |
| 246 | ]; |
| 247 | } |
| 248 | |
| 249 | protected function define_children_dependencies(): array { |
| 250 | return [ |
| 251 | Child_Dependency::for( self::ELEMENT_TYPE_CONTROLS ) |
| 252 | ->when( |
| 253 | Dependency_Manager::make()->where( [ |
| 254 | 'operator' => 'ne', |
| 255 | 'path' => [ 'show_controls' ], |
| 256 | 'value' => false, |
| 257 | ] ) |
| 258 | ) |
| 259 | ->position( Element_Position::last() ) |
| 260 | ->stash( true ) |
| 261 | ->default_model( |
| 262 | Element_Builder::make( self::ELEMENT_TYPE_CONTROLS ) |
| 263 | ->is_locked( true ) |
| 264 | ->hydrate_default_children( true ) |
| 265 | ->children( [ |
| 266 | Element_Builder::make( self::ELEMENT_TYPE_PLAY ) |
| 267 | ->hydrate_default_children( true ) |
| 268 | ->build(), |
| 269 | Element_Builder::make( self::ELEMENT_TYPE_PAUSE ) |
| 270 | ->hydrate_default_children( true ) |
| 271 | ->build(), |
| 272 | ] ) |
| 273 | ->build() |
| 274 | ), |
| 275 | ]; |
| 276 | } |
| 277 | |
| 278 | protected function define_allowed_child_types() { |
| 279 | return [ |
| 280 | self::ELEMENT_TYPE_CONTENT, |
| 281 | self::ELEMENT_TYPE_CONTROLS, |
| 282 | ]; |
| 283 | } |
| 284 | |
| 285 | public function get_script_depends() { |
| 286 | $global_depends = parent::get_script_depends(); |
| 287 | |
| 288 | if ( Plugin::$instance->preview->is_preview_mode() ) { |
| 289 | return array_merge( $global_depends, [ 'elementor-background-video-handler', 'elementor-background-video-preview-handler' ] ); |
| 290 | } |
| 291 | |
| 292 | return array_merge( $global_depends, [ 'elementor-background-video-handler' ] ); |
| 293 | } |
| 294 | |
| 295 | public function register_frontend_handlers() { |
| 296 | $assets_url = ELEMENTOR_ASSETS_URL; |
| 297 | $min_suffix = ( Utils::is_script_debug() || Utils::is_elementor_tests() ) ? '' : '.min'; |
| 298 | |
| 299 | wp_register_script( |
| 300 | 'elementor-background-video-handler', |
| 301 | "{$assets_url}js/background-video-handler{$min_suffix}.js", |
| 302 | [ Frontend_Assets_Loader::FRONTEND_HANDLERS_HANDLE, Frontend_Assets_Loader::ALPINEJS_HANDLE ], |
| 303 | ELEMENTOR_VERSION, |
| 304 | true |
| 305 | ); |
| 306 | |
| 307 | wp_register_script( |
| 308 | 'elementor-background-video-preview-handler', |
| 309 | "{$assets_url}js/background-video-preview-handler{$min_suffix}.js", |
| 310 | [ Frontend_Assets_Loader::FRONTEND_HANDLERS_HANDLE, Frontend_Assets_Loader::ALPINEJS_HANDLE ], |
| 311 | ELEMENTOR_VERSION, |
| 312 | true |
| 313 | ); |
| 314 | } |
| 315 | |
| 316 | protected function build_template_context(): array { |
| 317 | $settings = $this->get_atomic_settings(); |
| 318 | $video_start_time = $settings['start_time'] ?? null; |
| 319 | $video_end_time = $settings['end_time'] ?? null; |
| 320 | $video_timings = '#t=0'; |
| 321 | |
| 322 | if ( ! empty( $video_start_time ) ) { |
| 323 | $video_timings = '#t=' . $video_start_time; |
| 324 | } |
| 325 | |
| 326 | if ( ! empty( $video_end_time ) && $video_end_time > ( $video_start_time ?? 0 ) ) { |
| 327 | $video_timings .= ',' . $video_end_time; |
| 328 | } |
| 329 | |
| 330 | return array_merge( $this->build_base_template_context(), [ |
| 331 | 'video_timings' => $video_timings, |
| 332 | ] ); |
| 333 | } |
| 334 | |
| 335 | protected function get_templates(): array { |
| 336 | return [ |
| 337 | 'elementor/elements/atomic-background-video' => __DIR__ . '/atomic-background-video.html.twig', |
| 338 | ]; |
| 339 | } |
| 340 | } |
| 341 |