'', 'arrow-top' => '', 'arrow2-bottom' => '', 'arrow2-top' => '', 'arrow3-bottom' => '', 'arrow3-top' => '', 'asymmetric-bottom' => '', 'asymmetric-top' => '', 'asymmetric2-bottom' => '', 'asymmetric2-top' => '', 'asymmetric3-bottom' => '', 'asymmetric3-top' => '', 'asymmetric4-bottom' => '', 'asymmetric4-top' => '', 'clouds-bottom' => '', 'clouds-bottom2' => '', 'clouds-top' => '', 'clouds-top2' => '', 'clouds2-bottom' => '', 'clouds2-bottom2' => '', 'clouds2-top' => '', 'clouds2-top2' => '', 'curve-bottom' => '', 'curve-top' => '', 'curve2-bottom' => '', 'curve2-top' => '', 'graph-bottom' => '', 'graph-top' => '', 'graph2-bottom' => '', 'graph2-top' => '', 'graph3-bottom' => '', 'graph3-top' => '', 'graph4-bottom' => '', 'graph4-top' => '', 'mountains-bottom' => '', 'mountains-top' => '', 'mountains2-bottom' => '', 'mountains2-top' => '', 'ramp-bottom' => '', 'ramp-top' => '', 'ramp2-bottom' => '', 'ramp2-top' => '', 'slant-bottom' => '', 'slant-top' => '', 'slant2-bottom' => '', 'slant2-top' => '', 'triangle-bottom' => '', 'triangle-bottom2' => '', 'triangle-top' => '', 'triangle-top2' => '', 'wave-bottom' => '', 'wave-top' => '', 'wave2-bottom' => '', 'wave2-top' => '', 'waves-bottom' => '', 'waves-top' => '', 'waves2-bottom' => '', 'waves2-top' => '', ); /** * Filters the section divider paths. * * @param array $dividers Array list of available dividers. */ $this->dividers = apply_filters( 'et_section_dividers', $section_dividers ); if ( null === self::$data_utils ) { self::$data_utils = ET_Core_Data_Utils::instance(); } } /** * Retrieves fields for divider settings. * * @since 3.23 Add responsive settings on Divider Style. Add allowed units on some range fields. * * @param array $args Associative array for settings. * @return array Option settings. */ public function get_fields( array $args = array() ) { // Create an array so we don't get an error. $additional_options = array(); // Create the options by first creating the structure. $structure = array(); foreach ( array( 'top', 'bottom' ) as $placement ) : $structure[ "{$placement}_divider" ] = array( 'controls' => array( "{$placement}_divider_style" => array( 'label' => esc_html__( 'Divider Style', 'et_builder' ), 'description' => esc_html__( 'Select the divider shape that you would like to use. Shapes are represented visually within the list.', 'et_builder' ), 'type' => 'divider', 'options' => array( 'none' => et_builder_i18n( 'None' ), 'slant' => esc_html__( 'Slant', 'et_builder' ), 'slant2' => esc_html__( 'Slant 2', 'et_builder' ), 'arrow' => esc_html__( 'Arrow', 'et_builder' ), 'arrow2' => esc_html__( 'Arrow 2', 'et_builder' ), 'arrow3' => esc_html__( 'Arrow 3', 'et_builder' ), 'ramp' => esc_html__( 'Ramp', 'et_builder' ), 'ramp2' => esc_html__( 'Ramp 2', 'et_builder' ), 'curve' => esc_html__( 'Curve', 'et_builder' ), 'curve2' => esc_html__( 'Curve 2', 'et_builder' ), 'mountains' => esc_html__( 'Mountains', 'et_builder' ), 'mountains2' => esc_html__( 'Mountains 2', 'et_builder' ), 'wave' => esc_html__( 'Wave', 'et_builder' ), 'wave2' => esc_html__( 'Wave 2', 'et_builder' ), 'waves' => esc_html__( 'Waves', 'et_builder' ), 'waves2' => esc_html__( 'Waves 2', 'et_builder' ), 'asymmetric' => esc_html__( 'Asymmetric', 'et_builder' ), 'asymmetric2' => esc_html__( 'Asymmetric 2', 'et_builder' ), 'asymmetric3' => esc_html__( 'Asymmetric 3', 'et_builder' ), 'asymmetric4' => esc_html__( 'Asymmetric 4', 'et_builder' ), 'graph' => esc_html__( 'Graph', 'et_builder' ), 'graph2' => esc_html__( 'Graph 2', 'et_builder' ), 'graph3' => esc_html__( 'Graph 3', 'et_builder' ), 'graph4' => esc_html__( 'Graph 4', 'et_builder' ), 'triangle' => esc_html__( 'Triangle', 'et_builder' ), 'clouds' => esc_html__( 'Clouds', 'et_builder' ), 'clouds2' => esc_html__( 'Clouds 2', 'et_builder' ), ), 'default' => 'none', 'flip' => '', 'mobile_options' => true, ), "{$placement}_divider_color" => array( 'label' => esc_html__( 'Divider Color', 'et_builder' ), 'description' => esc_html__( 'Pick a color to use for the section divider. By default, it will assume the color of the section above or below this section to ensure a smooth transition.', 'et_builder' ), 'type' => 'color-alpha', 'default' => '', 'show_if_not' => array( "{$placement}_divider_style" => 'none', ), 'mobile_options' => true, ), "{$placement}_divider_height" => array( 'label' => esc_html__( 'Divider Height', 'et_builder' ), 'description' => esc_html__( 'Increase or decrease the height of the shape divider.', 'et_builder' ), 'type' => 'range', 'range_settings' => array( 'min' => 0, 'max' => 500, 'step' => 1, ), 'default' => '100px', 'hover' => 'tabs', 'allowed_units' => array( '%', 'em', 'rem', 'px', 'cm', 'mm', 'in', 'pt', 'pc', 'ex', 'vh', 'vw' ), 'default_unit' => 'px', 'show_if_not' => array( "{$placement}_divider_style" => 'none', ), 'mobile_options' => true, 'sticky' => true, ), "{$placement}_divider_repeat" => array( 'label' => esc_html__( 'Divider Horizontal Repeat', 'et_builder' ), 'description' => esc_html__( 'Choose how many times the shape divider should repeat. Setting to 1x will remove all repetition.', 'et_builder' ), 'type' => 'range', 'range_settings' => array( 'min' => 1, 'max' => 20, 'step' => 1, 'min_limit' => 1, // Changed to 1 from 0 since it's basically the same result for both values. ), 'default' => '1', // Dont use the fixed_unit in default value ( i.e. 1x, just use 1 ), or else input will return undefined. 'fixed_unit' => 'x', 'show_if_not' => array( "{$placement}_divider_style" => array( 'none', 'clouds', 'clouds2', 'triangle' ), ), 'mobile_options' => true, ), "{$placement}_divider_flip" => array( 'label' => esc_html__( 'Divider Flip', 'et_builder' ), 'description' => esc_html__( 'Flip the divider horizontally or vertically to change the shape and its direction.', 'et_builder' ), 'type' => 'multiple_buttons', 'options' => array( 'horizontal' => array( 'title' => esc_html__( 'Horizontal', 'et_builder' ), 'icon' => 'flip-horizontally', ), 'vertical' => array( 'title' => esc_html__( 'Vertical', 'et_builder' ), 'icon' => 'flip-vertically', ), ), 'toggleable' => true, 'multi_selection' => true, 'default' => '', 'show_if_not' => array( "{$placement}_divider_style" => 'none', ), 'mobile_options' => true, ), "{$placement}_divider_arrangement" => array( 'label' => esc_html__( 'Divider Arrangement', 'et_builder' ), 'description' => esc_html__( 'Dividers can be placed either above or below section content. If placed above section content, then modules and rows within the section will be hidden behind the divider when they overlap.', 'et_builder' ), 'type' => 'select', 'options' => array( 'above_content' => esc_html__( 'On Top Of Section Content', 'et_builder' ), 'below_content' => esc_html__( 'Underneath Section Content', 'et_builder' ), ), 'default' => 'below_content', 'show_if_not' => array( "{$placement}_divider_style" => 'none', 'fullwidth' => 'on', ), 'mobile_options' => true, ), ), ); // Automatically append responsive field foreach ( $structure[ "{$placement}_divider" ]['controls'] as $field_name => $field ) { if ( isset( $field['mobile_options'] ) && $field['mobile_options'] ) { $responsive_field_default = isset( $field['default'] ) ? $field['default'] : ''; // Tablet field $structure[ "{$placement}_divider" ]['controls'][ "{$field_name}_tablet" ] = array( 'type' => 'hidden', 'default' => $responsive_field_default, ); // Phone field $structure[ "{$placement}_divider" ]['controls'][ "{$field_name}_phone" ] = array( 'type' => 'hidden', 'default' => $responsive_field_default, ); // Last edited field $structure[ "{$placement}_divider" ]['controls'][ "{$field_name}_last_edited" ] = array( 'type' => 'hidden', 'default' => 'off|desktop', ); } } endforeach; // End foreach(). // Set our labels. $structure['bottom_divider']['label'] = et_builder_i18n( 'Bottom' ); $structure['top_divider']['label'] = et_builder_i18n( 'Top' ); $additional_options['divider_settings'] = array( 'label' => esc_html__( 'Dividers', 'et_builder' ), 'description' => esc_html__( 'Section dividers allow you to add creative shape transitions between different sections on your page.', 'et_builder' ), 'tab_slug' => $args['tab_slug'], 'toggle_slug' => $args['toggle_slug'], 'attr_suffix' => '', 'type' => 'composite', 'option_category' => 'layout', 'composite_type' => 'default', 'composite_structure' => $structure, ); return $additional_options; } /** * Process Section Divider * * Adds a CSS class to the section, determines orientaion of the SVG, encodes an SVG to use as data * for the background-image property. * * @since 3.23 Pass values parameter to support responsive settings. * @since 4.6.0 Add sticky style support. * * @param string $placement Whether it is the top or bottom divider. * @param array $atts Associative array of shortcode and their * respective values. * @param string $breakpoint ''|tablet|phone * @param array $values Existing responsive values. */ public function process_svg( $placement, $atts, $breakpoint = '', $values = array() ) { // add a class to the section. $this->classes[] = sprintf( 'et_pb_%s_divider', esc_attr( $placement ) ); // set some defaults. $previous_section = ! empty( $atts['prev_background_color'] ) ? $atts['prev_background_color'] : '#ffffff'; $next_section = ! empty( $atts['next_background_color'] ) ? $atts['next_background_color'] : '#ffffff'; // set a default based on whether it is the top or bottom divider. $default_color = ( 'top' === $placement ) ? $previous_section : $next_section; $color = ! empty( $atts[ "{$placement}_divider_color" ] ) ? $atts[ "{$placement}_divider_color" ] : $default_color; $height = ! empty( $atts[ "{$placement}_divider_height" ] ) ? $atts[ "{$placement}_divider_height" ] : '100px'; $height_hover = et_pb_hover_options()->get_value( "{$placement}_divider_height", $atts, false ); $repeat = ! empty( $atts[ "{$placement}_divider_repeat" ] ) ? floatval( $atts[ "{$placement}_divider_repeat" ] ) : 1; $flip = ( '' !== $atts[ "{$placement}_divider_flip" ] ) ? explode( '|', $atts[ "{$placement}_divider_flip" ] ) : array(); $arrangement = ! empty( $atts[ "{$placement}_divider_arrangement" ] ) ? $atts[ "{$placement}_divider_arrangement" ] : 'below_content'; $divider_style = et_pb_responsive_options()->get_any_value( $atts, "{$placement}_divider_style", '', true, $breakpoint ); $style = $divider_style . "-{$placement}"; $fullwidth = $atts['fullwidth']; // Apply adjustment for responsive styling if ( '' !== $breakpoint ) { // Get all responsive unique value. $values = et_pb_responsive_options()->get_any_responsive_values( $atts, array( "{$placement}_divider_color" => '', "{$placement}_divider_height" => '', "{$placement}_divider_repeat" => '', "{$placement}_divider_flip" => '', "{$placement}_divider_arrangement" => '', ), true, $breakpoint ); // Replace all default values. $color = ! empty( $values[ "{$placement}_divider_color" ] ) ? $values[ "{$placement}_divider_color" ] : $color; $height = ! empty( $values[ "{$placement}_divider_height" ] ) ? $values[ "{$placement}_divider_height" ] : $height; $repeat = ! empty( $values[ "{$placement}_divider_repeat" ] ) ? floatval( $values[ "{$placement}_divider_repeat" ] ) : $repeat; $flip = ! empty( $values[ "{$placement}_divider_flip" ] ) ? explode( '|', $values[ "{$placement}_divider_flip" ] ) : $flip; $arrangement = ! empty( $values[ "{$placement}_divider_arrangement" ] ) ? $values[ "{$placement}_divider_arrangement" ] : $arrangement; if ( ! empty( $values[ "{$placement}_divider_flip" ] ) && 'none' === $values[ "{$placement}_divider_flip" ] ) { $flip = array(); } } // Make sure that we don't divide by zero. if ( ! $repeat ) { $repeat = 1; } // let's make sure we flip the fight ones, yeah? // use the opposite SVG if ( in_array( 'vertical', $flip ) ) { switch ( $placement ) { case 'top': $style = $divider_style . '-bottom'; break; case 'bottom': $style = $divider_style . '-top'; break; } } // The SVG markup for the background. switch ( $style ) { case 'clouds-top': case 'clouds2-top': // we can use the viewBox to move down the image since it has a height of 86px $svg_markup = '%3$s'; break; case 'clouds-bottom': case 'clouds2-bottom': // we can use the viewBox to move up the image since it has a height of 86px $svg_markup = '%3$s'; break; case 'triangle-top': $svg_markup = '%3$s'; break; case 'triangle-bottom': $svg_markup = '%3$s'; break; default: $svg_markup = '%3$s'; break; } $divider_style = isset( $this->dividers[ $style ] ) ? $this->dividers[ $style ] : ''; $svg = sprintf( $svg_markup, $height, $color, $divider_style ); // encode the SVG so we can use it as data for background-image. $this->svg = base64_encode( $svg ); // phpcs:ignore // Build up our declaration. // bg-image $declaration['background-image'] = sprintf( 'url( data:image/svg+xml;base64,%s )', $this->svg ); // bg-size. the percent is how many times to repeat the image. if ( 0 === strpos( $style, 'clouds' ) ) { $declaration['background-size'] = 'cover'; switch ( $placement ) { case 'top': $declaration['background-position'] = ( 'top' === $placement || 'vertical' === $flip ) ? 'center top' : 'center bottom'; break; case 'bottom': $declaration['background-position'] = ( 'top' === $placement || 'vertical' !== $flip ) ? 'center top' : 'center bottom'; break; } } elseif ( 0 === strpos( $style, 'triangle' ) ) { $declaration['background-size'] = 'cover'; $declaration['background-position-x'] = 'center'; } else { // Adjusts for when percentages are being used. if ( 0 < strpos( $height, '%' ) ) { $declaration['background-size'] = sprintf( '%1$s%% 100%%', floatval( 100 / $repeat ) ); } else { $declaration['background-size'] = sprintf( '%1$s%% %2$s', floatval( 100 / $repeat ), $height ); } } // position $declaration[ $placement ] = 0; // height $declaration['height'] = $height; // z-index - determined by arrangement. $declaration['z-index'] = ( 'on' === $fullwidth || 'above_content' === $arrangement ) ? 10 : 1; $flip_styles = array(); // flipping the svg x|y if ( in_array( 'horizontal', $flip ) ) { $flip_styles[] = 'rotateY(180deg)'; } elseif ( '' !== $breakpoint ) { $flip_styles[] = 'rotateY(0)'; } if ( in_array( 'vertical', $flip ) ) { $flip_styles[] = 'rotateX(180deg)'; } elseif ( '' !== $breakpoint ) { $flip_styles[] = 'rotateX(0)'; } if ( ! empty( $flip_styles ) ) { $declaration['transform'] = implode( ' ', $flip_styles ); } // finally create our CSS declaration. $css = ''; foreach ( $declaration as $rule => $value ) { $css .= esc_html( "{$rule}:{$value};" ); } // prepare our selector. $selector = sprintf( '%%order_class%%.section_has_divider.et_pb_%1$s_divider .et_pb_%1$s_inside_divider', esc_attr( $placement ) ); // The styling of our section divider. $styling = array( 'selector' => $selector, 'declaration' => $css, ); // Apply media query if needed if ( in_array( $breakpoint, array( 'tablet', 'phone' ) ) ) { $query_map = array( 'tablet' => 'max_width_980', 'phone' => 'max_width_767', ); $styling['media_query'] = ET_Builder_Element::get_media_query( $query_map[ $breakpoint ] ); } ET_Builder_Element::set_style( 'et_pb_section', $styling ); // if we are on the first section and is the top divider. if ( 0 === $this->count && 'top' === $placement && '' === $breakpoint ) { // we will use a transparent bg. ET_Builder_Element::set_style( 'et_pb_section', array( 'selector' => $selector, 'declaration' => 'background-color: transparent;', ) ); } // Print Hover / Sticky height. $modes = array( 'hover', 'sticky' ); // sprintf() removes `%` while add_hover* and add_sticky* only recognize %%order_class%%. // thus append mode selector before $placement is re-added to the selector. $height_selector_base = '%%order_class%%.section_has_divider.et_pb_%1$s_divider .et_pb_%1$s_inside_divider'; foreach ( $modes as $mode ) { switch ( $mode ) { case 'hover': $helper = et_pb_hover_options(); $height_mode_selector = $helper->add_hover_to_order_class( $height_selector_base ); break; case 'sticky': $helper = et_pb_sticky_options(); $height_mode_selector = $helper->add_sticky_to_order_class( $height_selector_base, $helper->is_sticky_module( $atts ) ); break; } $height_mode = $helper->get_value( "{$placement}_divider_height", $atts, false ); if ( false === $height_mode ) { continue; } $css = ''; $height = $height_mode; $selector = sprintf( $height_mode_selector, esc_attr( $placement ) ); $declaration = array( 'height' => $height, ); // Adjusts for when percentages are being used. if ( 0 < strpos( $height, '%' ) ) { $declaration['background-size'] = sprintf( '%1$s%% 100%%', floatval( 100 / $repeat ) ); } else { $declaration['background-size'] = sprintf( '%1$s%% %2$s', floatval( 100 / $repeat ), $height ); } foreach ( $declaration as $rule => $value ) { $css .= esc_html( "{$rule}:{$value};" ); } ET_Builder_Element::set_style( 'et_pb_section', array( 'selector' => "$selector", 'declaration' => $css, ) ); } } /** * Returns a placeholder for the section only if it is set to be inside of the section. * * @param string $placement Whether it is the top or bottom * @return string HTML container */ public function get_svg( $placement ) { // we return a div to use for the divider return sprintf( '
', esc_attr( $placement ) ); } } return new ET_Builder_Module_Field_Divider();