use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
* Elementor column element.
* Elementor column handler class is responsible for initializing the column
class Element_Column extends Element_Base {
* Retrieve the column name.
* @return string Column name.
public function get_name() {
* Retrieve the element type, in this case `column`.
* @return string The type.
public static function get_type() {
* Retrieve the column title.
* @return string Column title.
public function get_title() {
return esc_html__( 'Column', 'elementor' );
* Retrieve the column icon.
* @return string Column icon.
public function get_icon() {
protected function is_dynamic_content(): bool {
* Retrieve the current section initial configuration.
* Adds more configuration on top of the controls list, the tabs assigned to
* the control, element name, type, icon and more. This method also adds
* @return array The initial config.
protected function get_initial_config() {
$config = parent::get_initial_config();
$config['controls'] = $this->get_controls();
$config['tabs_controls'] = $this->get_tabs_controls();
* Register column controls.
* Used to add new controls to the column element.
protected function register_controls() {
$this->start_controls_section(
'label' => esc_html__( 'Layout', 'elementor' ),
'tab' => Controls_Manager::TAB_LAYOUT,
// Element Name for the Navigator.
'label' => esc_html__( 'Title', 'elementor' ),
'type' => Controls_Manager::HIDDEN,
$active_breakpoint_keys = array_reverse( array_keys( Plugin::$instance->breakpoints->get_active_breakpoints() ) );
$inline_size_device_args = [
Breakpoints_Manager::BREAKPOINT_KEY_MOBILE => [ 'placeholder' => 100 ],
foreach ( $active_breakpoint_keys as $breakpoint_key ) {
if ( ! isset( $inline_size_device_args[ $breakpoint_key ] ) ) {
$inline_size_device_args[ $breakpoint_key ] = [];
$inline_size_device_args[ $breakpoint_key ] = array_merge_recursive(
$inline_size_device_args[ $breakpoint_key ],
if ( in_array( Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA, $active_breakpoint_keys, true ) ) {
$min_affected_device_value = Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA;
$min_affected_device_value = Breakpoints_Manager::BREAKPOINT_KEY_TABLET;
$this->add_responsive_control(
'label' => esc_html__( 'Column Width', 'elementor' ) . ' (%)',
'type' => Controls_Manager::NUMBER,
'device_args' => $inline_size_device_args,
'min_affected_device' => [
Breakpoints_Manager::BREAKPOINT_KEY_DESKTOP => $min_affected_device_value,
Breakpoints_Manager::BREAKPOINT_KEY_LAPTOP => $min_affected_device_value,
Breakpoints_Manager::BREAKPOINT_KEY_TABLET_EXTRA => $min_affected_device_value,
Breakpoints_Manager::BREAKPOINT_KEY_TABLET => $min_affected_device_value,
Breakpoints_Manager::BREAKPOINT_KEY_MOBILE_EXTRA => $min_affected_device_value,
'{{WRAPPER}}' => 'width: {{VALUE}}%',
$this->add_responsive_control(
'label' => esc_html__( 'Vertical Alignment', 'elementor' ),
'type' => Controls_Manager::SELECT,
'' => esc_html__( 'Default', 'elementor' ),
'top' => esc_html__( 'Top', 'elementor' ),
'center' => esc_html__( 'Middle', 'elementor' ),
'bottom' => esc_html__( 'Bottom', 'elementor' ),
'space-between' => esc_html__( 'Space Between', 'elementor' ),
'space-around' => esc_html__( 'Space Around', 'elementor' ),
'space-evenly' => esc_html__( 'Space Evenly', 'elementor' ),
'selectors_dictionary' => [
// TODO: The following line is for BC since 2.7.0.
'.elementor-bc-flex-widget {{WRAPPER}}.elementor-column .elementor-widget-wrap' => 'align-items: {{VALUE}}',
// This specificity is intended to make sure column css overwrites section css on vertical alignment (content_position).
'{{WRAPPER}}.elementor-column.elementor-element[data-element_type="column"] > .elementor-widget-wrap.elementor-element-populated' => 'align-content: {{VALUE}}; align-items: {{VALUE}};',
$this->add_responsive_control(
'label' => esc_html__( 'Horizontal Alignment', 'elementor' ),
'type' => Controls_Manager::SELECT,
'' => esc_html__( 'Default', 'elementor' ),
'flex-start' => esc_html__( 'Start', 'elementor' ),
'center' => esc_html__( 'Center', 'elementor' ),
'flex-end' => esc_html__( 'End', 'elementor' ),
'space-between' => esc_html__( 'Space Between', 'elementor' ),
'space-around' => esc_html__( 'Space Around', 'elementor' ),
'space-evenly' => esc_html__( 'Space Evenly', 'elementor' ),
'{{WRAPPER}}.elementor-column > .elementor-widget-wrap' => 'justify-content: {{VALUE}}',
$optimized_markup = Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
$space_between_widgets = $optimized_markup
? '--kit-widget-spacing: {{VALUE}}px'
: 'margin-bottom: {{VALUE}}px';
$this->add_responsive_control(
'label' => esc_html__( 'Widgets Space', 'elementor' ) . ' (px)',
'type' => Controls_Manager::NUMBER,
'{{WRAPPER}} > .elementor-widget-wrap > .elementor-widget:not(.elementor-widget__width-auto):not(.elementor-widget__width-initial):not(:last-child):not(.elementor-absolute)' => $space_between_widgets, // Need the full path for exclude the inner section.
'' => esc_html__( 'Default', 'elementor' ),
] + array_combine( $possible_tags, $possible_tags );
'label' => esc_html__( 'HTML Tag', 'elementor' ),
'type' => Controls_Manager::SELECT,
$this->end_controls_section();
$this->start_controls_section(
'label' => esc_html__( 'Background', 'elementor' ),
'tab' => Controls_Manager::TAB_STYLE,
$this->start_controls_tabs( 'tabs_background' );
$this->start_controls_tab(
'label' => esc_html__( 'Normal', 'elementor' ),
$this->add_group_control(
Group_Control_Background::get_type(),
'types' => [ 'classic', 'gradient', 'slideshow' ],
'selector' => '{{WRAPPER}}:not(.elementor-motion-effects-element-type-background) > .elementor-widget-wrap, {{WRAPPER}} > .elementor-widget-wrap > .elementor-motion-effects-container > .elementor-motion-effects-layer',
'frontend_available' => true,
'handle_slideshow_asset_loading',
'type' => Controls_Manager::HIDDEN,
'name' => 'background_background',
'name' => 'background_background',
$this->end_controls_tab();
$this->start_controls_tab(
'label' => esc_html__( 'Hover', 'elementor' ),
$this->add_group_control(
Group_Control_Background::get_type(),
'name' => 'background_hover',
'selector' => '{{WRAPPER}}:hover > .elementor-element-populated',
'background_hover_transition',
'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
'type' => Controls_Manager::SLIDER,
$this->end_controls_tab();
$this->end_controls_tabs();
$this->end_controls_section();
// Section Column Background Overlay.
$this->start_controls_section(
'section_background_overlay',
'label' => esc_html__( 'Background Overlay', 'elementor' ),
'tab' => Controls_Manager::TAB_STYLE,
'background_background' => [ 'classic', 'gradient' ],
$this->start_controls_tabs( 'tabs_background_overlay' );
$this->start_controls_tab(
'tab_background_overlay_normal',
'label' => esc_html__( 'Normal', 'elementor' ),
$this->add_group_control(
Group_Control_Background::get_type(),
'name' => 'background_overlay',
'selector' => '{{WRAPPER}} > .elementor-element-populated > .elementor-background-overlay',
$this->add_responsive_control(
'background_overlay_opacity',
'label' => esc_html__( 'Opacity', 'elementor' ),
'type' => Controls_Manager::SLIDER,
'{{WRAPPER}} > .elementor-element-populated > .elementor-background-overlay' => 'opacity: {{SIZE}};',
'background_overlay_background' => [ 'classic', 'gradient' ],
$this->add_group_control(
Group_Control_Css_Filter::get_type(),
'selector' => '{{WRAPPER}} > .elementor-element-populated > .elementor-background-overlay',
'label' => esc_html__( 'Blend Mode', 'elementor' ),
'type' => Controls_Manager::SELECT,
'' => esc_html__( 'Normal', 'elementor' ),
'multiply' => esc_html__( 'Multiply', 'elementor' ),
'screen' => esc_html__( 'Screen', 'elementor' ),
'overlay' => esc_html__( 'Overlay', 'elementor' ),
'darken' => esc_html__( 'Darken', 'elementor' ),
'lighten' => esc_html__( 'Lighten', 'elementor' ),
'color-dodge' => esc_html__( 'Color Dodge', 'elementor' ),
'saturation' => esc_html__( 'Saturation', 'elementor' ),
'color' => esc_html__( 'Color', 'elementor' ),
'difference' => esc_html__( 'Difference', 'elementor' ),
'exclusion' => esc_html__( 'Exclusion', 'elementor' ),
'hue' => esc_html__( 'Hue', 'elementor' ),
'luminosity' => esc_html__( 'Luminosity', 'elementor' ),
'{{WRAPPER}} > .elementor-element-populated > .elementor-background-overlay' => 'mix-blend-mode: {{VALUE}}',
$this->end_controls_tab();
$this->start_controls_tab(
'tab_background_overlay_hover',
'label' => esc_html__( 'Hover', 'elementor' ),
$this->add_group_control(
Group_Control_Background::get_type(),
'name' => 'background_overlay_hover',
'selector' => '{{WRAPPER}}:hover > .elementor-element-populated > .elementor-background-overlay',
$this->add_responsive_control(
'background_overlay_hover_opacity',
'label' => esc_html__( 'Opacity', 'elementor' ),
'type' => Controls_Manager::SLIDER,