); $flex_size_values = array( $flex_child_layout_values['max'], $flex_child_layout_values['fixed'], ); if ( null === $viewport_overrides || $has_viewport_property_override( 'selfStretch' ) || $has_viewport_property_override( 'flexSize' ) ) { if ( null !== $viewport_overrides && ( $flex_child_layout_values['fit'] === $self_stretch || $flex_child_layout_values['grow'] === $self_stretch ) && in_array( $base_self_stretch, $flex_size_values, true ) && isset( $base_child_layout['flexSize'] ) ) { $child_layout_declarations['flex-basis'] = 'unset'; if ( $flex_child_layout_values['fixed'] === $base_self_stretch ) { $child_layout_declarations['flex-shrink'] = 'unset'; } } if ( in_array( $self_stretch, $flex_size_values, true ) && isset( $child_layout['flexSize'] ) ) { $child_layout_declarations['flex-basis'] = $child_layout['flexSize']; if ( $flex_child_layout_values['fixed'] === $self_stretch ) { $child_layout_declarations['flex-shrink'] = '0'; } elseif ( null !== $viewport_overrides && $flex_child_layout_values['fixed'] === $base_self_stretch ) { $child_layout_declarations['flex-shrink'] = 'unset'; } $child_layout_declarations['box-sizing'] = 'border-box'; } elseif ( $flex_child_layout_values['grow'] === $self_stretch ) { $child_layout_declarations['flex-grow'] = '1'; } } $column_start = $child_layout['columnStart'] ?? null; $column_span = $child_layout['columnSpan'] ?? null; if ( null === $viewport_overrides || $has_viewport_property_override( 'columnStart' ) || $has_viewport_property_override( 'columnSpan' ) ) { if ( $column_start && $column_span ) { $child_layout_declarations['grid-column'] = "$column_start / span $column_span"; } elseif ( $column_start ) { $child_layout_declarations['grid-column'] = "$column_start"; } elseif ( $column_span ) { $child_layout_declarations['grid-column'] = "span $column_span"; } } $row_start = $child_layout['rowStart'] ?? null; $row_span = $child_layout['rowSpan'] ?? null; if ( null === $viewport_overrides || $has_viewport_property_override( 'rowStart' ) || $has_viewport_property_override( 'rowSpan' ) ) { if ( $row_start && $row_span ) { $child_layout_declarations['grid-row'] = "$row_start / span $row_span"; } elseif ( $row_start ) { $child_layout_declarations['grid-row'] = "$row_start"; } elseif ( $row_span ) { $child_layout_declarations['grid-row'] = "span $row_span"; } } if ( ! empty( $child_layout_declarations ) ) { $child_layout_styles[] = array( 'selector' => $selector, 'declarations' => $child_layout_declarations, ); } $minimum_column_width = $parent_layout['minimumColumnWidth'] ?? null; $column_count = $parent_layout['columnCount'] ?? null; /* * If columnSpan or columnStart is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, * the columnSpan should be removed once the grid is smaller than the span, and columnStart should be removed * once the grid has less columns than the start. * If there's a minimumColumnWidth, the grid is responsive. But if the minimumColumnWidth value wasn't changed, it won't be set. * In that case, if columnCount doesn't exist, we can assume that the grid is responsive. */ if ( null === $viewport_overrides && ( $column_span || $column_start ) && ( $minimum_column_width || ! $column_count ) ) { $column_span_number = floatval( $column_span ); $column_start_number = floatval( $column_start ); $parent_column_width = $minimum_column_width ? $minimum_column_width : '12rem'; $parent_column_value = floatval( $parent_column_width ); $parent_column_unit = explode( $parent_column_value, $parent_column_width ); $num_cols_to_break_at = 2; if ( $column_span_number && $column_start_number ) { $num_cols_to_break_at = $column_start_number + $column_span_number - 1; } elseif ( $column_span_number ) { $num_cols_to_break_at = $column_span_number; } else { $num_cols_to_break_at = $column_start_number; } /* * If there is no unit, the width has somehow been mangled so we reset both unit and value * to defaults. * Additionally, the unit should be one of px, rem or em, so that also needs to be checked. */ if ( count( $parent_column_unit ) <= 1 ) { $parent_column_unit = 'rem'; $parent_column_value = 12; } else { $parent_column_unit = $parent_column_unit[1]; if ( ! in_array( $parent_column_unit, array( 'px', 'rem', 'em' ), true ) ) { $parent_column_unit = 'rem'; } } /* * A default gap value is used for this computation because custom gap values may not be * viable to use in the computation of the container query value. */ $default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5; $container_query_value = $num_cols_to_break_at * $parent_column_value + ( $num_cols_to_break_at - 1 ) * $default_gap_value; $minimum_container_query_value = $parent_column_value * 2 + $default_gap_value - 1; $container_query_value = max( $container_query_value, $minimum_container_query_value ) . $parent_column_unit; // If a span is set we want to preserve it as long as possible, otherwise we just reset the value. $grid_column_value = $column_span && $column_span > 1 ? '1/-1' : 'auto'; $child_layout_styles[] = array( 'rules_group' => "@container (max-width: $container_query_value )", 'selector' => $selector, 'declarations' => array( 'grid-column' => $grid_column_value, 'grid-row' => 'auto', ), ); } return $child_layout_styles; } /** * Returns layout definitions, keyed by layout type. * * Provides a common definition of slugs, classnames, base styles, and spacing styles for each layout type. * When making changes or additions to layout definitions, the corresponding JavaScript definitions should * also be updated. * * @since 6.3.0 * @since 6.6.0 Updated specificity for compatibility with 0-1-0 global styles specificity. * @access private * * @return array[] Layout definitions. */ function wp_get_layout_definitions() { $layout_definitions = array( 'default' => array( 'name' => 'default', 'slug' => 'flow', 'className' => 'is-layout-flow', 'baseStyles' => array( array( 'selector' => ' > .alignleft', 'rules' => array( 'float' => 'left', 'margin-inline-start' => '0', 'margin-inline-end' => '2em', ), ), array( 'selector' => ' > .alignright', 'rules' => array( 'float' => 'right', 'margin-inline-start' => '2em', 'margin-inline-end' => '0', ), ), array( 'selector' => ' > .aligncenter', 'rules' => array( 'margin-left' => 'auto !important', 'margin-right' => 'auto !important', ), ), ), 'spacingStyles' => array( array( 'selector' => ' > :first-child', 'rules' => array( 'margin-block-start' => '0', ), ), array( 'selector' => ' > :last-child', 'rules' => array( 'margin-block-end' => '0', ), ), array( 'selector' => ' > *', 'rules' => array( 'margin-block-start' => null, 'margin-block-end' => '0', ), ), ), ), 'constrained' => array( 'name' => 'constrained', 'slug' => 'constrained', 'className' => 'is-layout-constrained', 'baseStyles' => array( array( 'selector' => ' > .alignleft', 'rules' => array( 'float' => 'left', 'margin-inline-start' => '0', 'margin-inline-end' => '2em', ), ), array( 'selector' => ' > .alignright', 'rules' => array( 'float' => 'right', 'margin-inline-start' => '2em', 'margin-inline-end' => '0', ), ), array( 'selector' => ' > .aligncenter', 'rules' => array( 'margin-left' => 'auto !important', 'margin-right' => 'auto !important', ), ), array( 'selector' => ' > :where(:not(.alignleft):not(.alignright):not(.alignfull))', 'rules' => array( 'max-width' => 'var(--wp--style--global--content-size)', 'margin-left' => 'auto !important', 'margin-right' => 'auto !important', ), ), array( 'selector' => ' > .alignwide', 'rules' => array( 'max-width' => 'var(--wp--style--global--wide-size)', ), ), ), 'spacingStyles' => array( array( 'selector' => ' > :first-child', 'rules' => array( 'margin-block-start' => '0', ), ), array( 'selector' => ' > :last-child', 'rules' => array( 'margin-block-end' => '0', ), ), array( 'selector' => ' > *', 'rules' => array( 'margin-block-start' => null, 'margin-block-end' => '0', ), ), ), ), 'flex' => array( 'name' => 'flex', 'slug' => 'flex', 'className' => 'is-layout-flex', 'displayMode' => 'flex', 'baseStyles' => array( array( 'selector' => '', 'rules' => array( 'flex-wrap' => 'wrap', 'align-items' => 'center', ), ), array( 'selector' => ' > :is(*, div)', // :is(*, div) instead of just * increases the specificity by 001. 'rules' => array( 'margin' => '0', ), ), ), 'spacingStyles' => array( array( 'selector' => '', 'rules' => array( 'gap' => null, ), ), ), ), 'grid' => array( 'name' => 'grid', 'slug' => 'grid', 'className' => 'is-layout-grid', 'displayMode' => 'grid', 'baseStyles' => array( array( 'selector' => ' > :is(*, div)', // :is(*, div) instead of just * increases the specificity by 001. 'rules' => array( 'margin' => '0', ), ), ), 'spacingStyles' => array( array( 'selector' => '', 'rules' => array( 'gap' => null, ), ), ), ), ); return $layout_definitions; } /** * Registers the layout block attribute for block types that support it. * * @since 5.8.0 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`. * @access private * * @param WP_Block_Type $block_type Block Type. */ function wp_register_layout_support( $block_type ) { $support_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false ); if ( $support_layout ) { if ( ! $block_type->attributes ) { $block_type->attributes = array(); } if ( ! array_key_exists( 'layout', $block_type->attributes ) ) { $block_type->attributes['layout'] = array( 'type' => 'object', ); } } } /** * Generates the CSS corresponding to the provided layout. * * @since 5.9.0 * @since 6.1.0 Added `$block_spacing` param, use style engine to enqueue styles. * @since 6.3.0 Added grid layout type. * @since 6.6.0 Removed duplicated selector from layout styles. * Enabled negative margins for alignfull children of blocks with custom padding. * @since 7.1.0 Added options array with options to process responsive styles. * @access private * * @param string $selector CSS selector. * @param array $layout Layout object. The one that is passed has already checked * the existence of default block layout. * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false. * @param string|string[]|null $gap_value Optional. The block gap value to apply. Default null. * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the editor. Default false. * @param string|array $fallback_gap_value Optional. The block gap value to apply. If it's an array expected properties are "top" and/or "left". Default '0.5em'. * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null. * @param array $options { * Optional. Extra options for internal callers. Default empty array. * * @type array $viewport_overrides An array of layout property overrides for the sake of style generation, * keyed by property name. * @type string|null $rules_group Optional group name for the rules. Default null. * @type bool $has_block_gap_override Whether the block gap has been overridden. Default false. * } * @return string CSS styles on success. Else, empty string. */ function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null, $options = array() ) { $base_layout = is_array( $layout ) ? $layout : array(); $viewport_overrides = $options['viewport_overrides'] ?? null; $layout_for_styles = null === $viewport_overrides ? $base_layout : array_replace( $base_layout, $viewport_overrides ); $layout_type = $base_layout['type'] ?? 'default'; $rules_group = $options['rules_group'] ?? null; $has_block_gap_override = ! empty( $options['has_block_gap_override'] ); $should_output_block_gap = null === $viewport_overrides || $has_block_gap_override; /* * Viewport styles only store changed fields. If a field is present with null, * the user cleared a value inherited from the default viewport, so check * whether the key exists rather than whether the value is truthy. */ $has_viewport_property_override = static function ( $property ) use ( $viewport_overrides ) { return array_key_exists( $property, $viewport_overrides ); }; $layout_styles = array(); if ( 'default' === $layout_type ) { if ( $has_block_gap_support && $should_output_block_gap ) { if ( is_array( $gap_value ) ) { $gap_value = $gap_value['top'] ?? null; } if ( null !== $gap_value && ! $should_skip_gap_serialization ) { // Get spacing CSS variable from preset value if provided. if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $gap_value, '|' ) + 1; $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); $gap_value = "var(--wp--preset--spacing--$slug)"; } array_push( $layout_styles, array( 'selector' => "$selector > *", 'declarations' => array( 'margin-block-start' => '0', 'margin-block-end' => '0', ), ), array( 'selector' => "$selector > * + *", 'declarations' => array( 'margin-block-start' => $gap_value, 'margin-block-end' => '0', ), ) ); } } } elseif ( 'constrained' === $layout_type ) { $content_size = $layout_for_styles['contentSize'] ?? ''; $wide_size = $layout_for_styles['wideSize'] ?? ''; $justify_content = $layout_for_styles['justifyContent'] ?? 'center'; // Check if viewport-specific ("override") values exist. Null values are valid and mean the user cleared a value inherited from the default viewport. $has_justify_content_override = null !== $viewport_overrides && $has_viewport_property_override( 'justifyContent' ); $has_content_size_override = null !== $viewport_overrides && $has_viewport_property_override( 'contentSize' ); $has_wide_size_override = null !== $viewport_overrides && $has_viewport_property_override( 'wideSize' ); /* * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific * value for contentSize or wideSize. If a viewport clears a custom constrained size, reset to the global layout variable. */ $should_output_constrained_sizes = null === $viewport_overrides || $has_content_size_override || $has_wide_size_override; $is_resetting_constrained_sizes = null !== $viewport_overrides && ( ( $has_content_size_override && ! $content_size ) || ( $has_wide_size_override && ! $wide_size ) ); // If a viewport clears a custom constrained size, reset to the global layout variable. $all_max_width_value = $content_size ? $content_size : ( $wide_size && ! $has_content_size_override ? $wide_size : 'var(--wp--style--global--content-size, none)' ); $wide_max_width_value = $wide_size ? $wide_size : ( $content_size && ! $has_wide_size_override ? $content_size : 'var(--wp--style--global--wide-size, none)' ); // Make sure there is a single CSS rule, and all tags are stripped for security. $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); $wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] ); $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important'; $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important'; if ( $should_output_constrained_sizes && ( $content_size || $wide_size || $is_resetting_constrained_sizes ) ) { $content_size_declarations = array( 'max-width' => $all_max_width_value, ); if ( null === $viewport_overrides || $has_justify_content_override ) { $content_size_declarations['margin-left'] = $margin_left; $content_size_declarations['margin-right'] = $margin_right; } array_push( $layout_styles, array( 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 'declarations' => $content_size_declarations, ), array( 'selector' => "$selector > .alignwide", 'declarations' => array( 'max-width' => $wide_max_width_value ), ), array( 'selector' => "$selector .alignfull", 'declarations' => array( 'max-width' => 'none' ), ) ); } if ( null === $viewport_overrides && isset( $block_spacing ) ) { $block_spacing_values = wp_style_engine_get_styles( array( 'spacing' => $block_spacing, ) ); /* * Handle negative margins for alignfull children of blocks with custom padding set. * They're added separately because padding might only be set on one side. */ if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { $padding_right = $block_spacing_values['declarations']['padding-right']; // Add unit if 0. if ( '0' === $padding_right ) { $padding_right = '0px'; } $layout_styles[] = array( 'selector' => "$selector > .alignfull", 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), ); } if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { $padding_left = $block_spacing_values['declarations']['padding-left']; // Add unit if 0. if ( '0' === $padding_left ) { $padding_left = '0px'; } $layout_styles[] = array( 'selector' => "$selector > .alignfull", 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), ); } } if ( $has_justify_content_override && ! $should_output_constrained_sizes ) { $layout_styles[] = array( 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 'declarations' => array( 'margin-left' => $margin_left, 'margin-right' => $margin_right, ), ); } elseif ( null === $viewport_overrides ) { if ( 'left' === $justify_content ) { $layout_styles[] = array( 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 'declarations' => array( 'margin-left' => '0 !important' ), ); } if ( 'right' === $justify_content ) { $layout_styles[] = array( 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 'declarations' => array( 'margin-right' => '0 !important' ), ); } } if ( $has_block_gap_support && $should_output_block_gap ) { if ( is_array( $gap_value ) ) { $gap_value = $gap_value['top'] ?? null; } if ( null !== $gap_value && ! $should_skip_gap_serialization ) { // Get spacing CSS variable from preset value if provided. if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $gap_value, '|' ) + 1; $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); $gap_value = "var(--wp--preset--spacing--$slug)"; } array_push( $layout_styles, array( 'selector' => "$selector > *", 'declarations' => array( 'margin-block-start' => '0', 'margin-block-end' => '0', ), ), array( 'selector' => "$selector > * + *", 'declarations' => array( 'margin-block-start' => $gap_value, 'margin-block-end' => '0', ), ) ); } } } elseif ( 'flex' === $layout_type ) { $layout_orientation = $layout_for_styles['orientation'] ?? 'horizontal'; $justify_content_options = array( 'left' => 'flex-start', 'right' => 'flex-end', 'center' => 'center', ); $vertical_alignment_options = array( 'top' => 'flex-start', 'center' => 'center', 'bottom' => 'flex-end', ); if ( 'horizontal' === $layout_orientation ) { $justify_content_options += array( 'space-between' => 'space-between' ); $vertical_alignment_options += array( 'stretch' => 'stretch' ); } else { $justify_content_options += array( 'stretch' => 'stretch' ); $vertical_alignment_options += array( 'space-between' => 'space-between' ); } /* * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific * value for any of the flex properties. */ $should_output_flex_wrap = null === $viewport_overrides || $has_viewport_property_override( 'flexWrap' ); $should_output_flex_orientation = null === $viewport_overrides || $has_viewport_property_override( 'orientation' ); $should_output_flex_justification = null === $viewport_overrides || $has_viewport_property_override( 'justifyContent' ) || $has_viewport_property_override( 'orientation' ); $should_output_flex_alignment = null === $viewport_overrides || $has_viewport_property_override( 'verticalAlignment' ) || $has_viewport_property_override( 'orientation' ); if ( $should_output_flex_wrap && ! empty( $layout_for_styles['flexWrap'] ) && 'nowrap' === $layout_for_styles['flexWrap'] ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'flex-wrap' => 'nowrap' ), ); } if ( $has_block_gap_support && $should_output_block_gap && isset( $gap_value ) ) { $combined_gap_value = ''; $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); foreach ( $gap_sides as $gap_side ) { $process_value = $gap_value; if ( is_array( $gap_value ) ) { if ( is_array( $fallback_gap_value ) ) { $fallback_value = $fallback_gap_value[ $gap_side ] ?? reset( $fallback_gap_value ); } else { $fallback_value = $fallback_gap_value; } $process_value = $gap_value[ $gap_side ] ?? $fallback_value; } // Get spacing CSS variable from preset value if provided. if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $process_value, '|' ) + 1; $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) ); $process_value = "var(--wp--preset--spacing--$slug)"; } $combined_gap_value .= "$process_value "; } $gap_value = trim( $combined_gap_value ); if ( null !== $gap_value && ! $should_skip_gap_serialization ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'gap' => $gap_value ), ); } } if ( 'horizontal' === $layout_orientation ) { /* * Add this style only if is not empty for backwards compatibility, * since we intend to convert blocks that had flex layout implemented * by custom css. */ if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'justify-content' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ), ); } if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ), ); } } else { if ( $should_output_flex_orientation ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'flex-direction' => 'column' ), ); } if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'align-items' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ), ); } elseif ( $should_output_flex_justification ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'align-items' => 'flex-start' ), ); } if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ), ); } } } elseif ( 'grid' === $layout_type ) { /* * If the gap value is an array, we use the "left" value because it represents the vertical gap, which * is the relevant one for computation of responsive grid columns. */ if ( is_array( $fallback_gap_value ) ) { $responsive_gap_value = $fallback_gap_value['left'] ?? reset( $fallback_gap_value ); } else { $responsive_gap_value = $fallback_gap_value; } if ( $has_block_gap_support && isset( $gap_value ) ) { $combined_gap_value = ''; $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); foreach ( $gap_sides as $gap_side ) { $process_value = $gap_value; if ( is_array( $gap_value ) ) { if ( is_array( $fallback_gap_value ) ) { $fallback_value = $fallback_gap_value[ $gap_side ] ?? reset( $fallback_gap_value ); } else { $fallback_value = $fallback_gap_value; } $process_value = $gap_value[ $gap_side ] ?? $fallback_value; } // Get spacing CSS variable from preset value if provided. if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { $index_to_splice = strrpos( $process_value, '|' ) + 1; $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) ); $process_value = "var(--wp--preset--spacing--$slug)"; } $combined_gap_value .= "$process_value "; } $gap_value = trim( $combined_gap_value ); $responsive_gap_value = $gap_value; } // Ensure 0 values have a unit so they work in calc(). if ( '0' === $responsive_gap_value || 0 === $responsive_gap_value ) { $responsive_gap_value = '0px'; } /* * Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific * value for any of the grid properties. */ $should_output_grid_columns = null === $viewport_overrides || $has_viewport_property_override( 'minimumColumnWidth' ) || $has_viewport_property_override( 'columnCount' ) || $has_viewport_property_override( 'autoFit' ); $uses_gap_in_grid_columns = ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ); if ( $has_block_gap_override && $uses_gap_in_grid_columns ) { $should_output_grid_columns = true; } $should_output_grid_rows = ( null === $viewport_overrides || $has_viewport_property_override( 'rowCount' ) ) && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['rowCount'] ); $grid_declarations = array(); /* * When enabled, columns stretch to fill the available space using * `auto-fit`; otherwise empty tracks are preserved with `auto-fill`. */ $auto_placement = ! empty( $layout_for_styles['autoFit'] ) ? 'auto-fit' : 'auto-fill'; if ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ) ) { $max_value = 'max(min(' . $layout_for_styles['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $layout_for_styles['columnCount'] . ' - 1))) /' . $layout_for_styles['columnCount'] . ')'; $grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(' . $max_value . ', 1fr))'; } elseif ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) ) { $grid_declarations['grid-template-columns'] = 'repeat(' . $layout_for_styles['columnCount'] . ', minmax(0, 1fr))'; } elseif ( $should_output_grid_columns ) { $minimum_column_width = ! empty( $layout_for_styles['minimumColumnWidth'] ) ? $layout_for_styles['minimumColumnWidth'] : '12rem'; $grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(min(' . $minimum_column_width . ', 100%), 1fr))'; } if ( ! empty( $grid_declarations ) ) { $base_has_container_type = empty( $base_layout['columnCount'] ) || ( ! empty( $base_layout['columnCount'] ) && ! empty( $base_layout['minimumColumnWidth'] ) ); if ( empty( $layout_for_styles['columnCount'] ) || ! empty( $layout_for_styles['minimumColumnWidth'] ) ) { if ( null === $viewport_overrides || ! $base_has_container_type ) { $grid_declarations['container-type'] = 'inline-size'; } } $layout_styles[] = array( 'selector' => $selector, 'declarations' => $grid_declarations, ); } if ( $should_output_grid_rows ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout_for_styles['rowCount'] . ', minmax(1rem, auto))' ), ); } if ( $has_block_gap_support && $should_output_block_gap && null !== $gap_value && ! $should_skip_gap_serialization ) { $layout_styles[] = array( 'selector' => $selector, 'declarations' => array( 'gap' => $gap_value ), ); } } if ( ! empty( $layout_styles ) ) { if ( ! empty( $rules_group ) ) { foreach ( $layout_styles as $index => $layout_style ) { $layout_styles[ $index ]['rules_group'] = $rules_group; } } /* * Add to the style engine store to enqueue and render layout styles. * Return compiled layout styles to retain backwards compatibility. * Since https://github.com/WordPress/gutenberg/pull/42452, * wp_enqueue_block_support_styles is no longer called in this block supports file. */ return wp_style_engine_get_stylesheet_from_css_rules( $layout_styles, array( 'context' => 'block-supports', 'prettify' => false, ) ); } return ''; } /** * Renders the layout config to the block wrapper. * * @since 5.8.0 * @since 6.3.0 Adds compound class to layout wrapper for global spacing styles. * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`. * @since 6.6.0 Removed duplicate container class from layout styles. * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_render_layout_support_flag( $block_content, $block ) { static $global_styles = null; $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); $block_supports_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false ); $style_attr = $block['attrs']['style'] ?? array(); /* * A block with no layout support and no style attribute at all cannot * produce layout output, so return before resolving global settings. * * Resolving settings is not read-only: on a cold cache it queries the * user's `wp_global_styles` post, which fires `the_posts`. A callback on * that hook that renders blocks re-enters this filter, and the content it * renders at that point is the global styles post itself, which parses to a * single block with no name and no attributes. Without this return that * block resolves settings again and the recursion has no base case. */ if ( ! $block_supports_layout && empty( $style_attr ) ) { return $block_content; } $global_settings = wp_get_global_settings(); $viewport_settings = $global_settings['viewport'] ?? null; $responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings ); $child_layout = $style_attr['layout'] ?? null; /* * Collect responsive viewport child layout overrides so that a block with * only responsive child layout (no base child layout) is still processed. */ $viewport_child_layouts = array(); foreach ( $responsive_media_queries as $breakpoint => $media_query ) { $viewport_child = wp_get_layout_child_values( $style_attr[ $breakpoint ]['layout'] ?? null ); if ( ! empty( $viewport_child ) ) { $viewport_child_layouts[ $breakpoint ] = array( 'media_query' => $media_query, 'child_layout' => $viewport_child, ); } } if ( ! $block_supports_layout && ! $child_layout && empty( $viewport_child_layouts ) ) { return $block_content; } $outer_class_names = array(); // Child layout specific logic. if ( $child_layout || ! empty( $viewport_child_layouts ) ) { $base_child_layout = wp_get_layout_child_values( $child_layout ); $parent_layout = $block['parentLayout'] ?? array(); /* * Generates a unique class for child block layout styles. * * To ensure consistent class generation across different page renders, * only properties that affect layout styling are used. These properties * come from `$block['attrs']['style']['layout']`, viewport overrides in * `$block['attrs']['style'][$breakpoint]['layout']`, and `$block['parentLayout']`. * * As long as these properties coincide, the generated class will be the same. */ $container_content_hash_input = array( 'layout' => $base_child_layout, 'parentLayout' => array_intersect_key( $parent_layout, array_flip( array( 'minimumColumnWidth', 'columnCount' ) ) ), ); foreach ( $viewport_child_layouts as $breakpoint => $viewport_data ) { $container_content_hash_input[ $breakpoint ] = $viewport_data['child_layout']; } $container_content_class = wp_unique_id_from_values( $container_content_hash_input, 'wp-container-content-' ); $child_layout_styles = wp_get_child_layout_style_rules( ".$container_content_class", $base_child_layout, $parent_layout ); /* * Emit responsive child layout CSS using the same container-content class * so that base and responsive child layout share the exact same selector. */ foreach ( $viewport_child_layouts as $viewport_data ) { $viewport_child_styles = wp_get_child_layout_style_rules( ".$container_content_class", $base_child_layout, $parent_layout, $viewport_data['child_layout'] ); foreach ( $viewport_child_styles as $index => $rule ) { $viewport_child_styles[ $index ]['rules_group'] = $viewport_data['media_query']; } $child_layout_styles = array_merge( $child_layout_styles, $viewport_child_styles ); } /* * Add to the style engine store to enqueue and render layout styles. * Return styles here just to check if any exist. */ $child_css = wp_style_engine_get_stylesheet_from_css_rules( $child_layout_styles, array( 'context' => 'block-supports', 'prettify' => false, ) ); if ( $child_css ) { $outer_class_names[] = $container_content_class; } } // Prep the processor for modifying the block output. $processor = new WP_HTML_Tag_Processor( $block_content ); // Having no tags implies there are no tags onto which to add class names. if ( ! $processor->next_tag() ) { return $block_content; } /* * A block may not support layout but still be affected by a parent block's layout. * * In these cases add the appropriate class names and then return early; there's * no need to investigate on this block whether additional layout constraints apply. */ if ( ! $block_supports_layout && ! empty( $outer_class_names ) ) { foreach ( $outer_class_names as $class_name ) { $processor->add_class( $class_name ); } return $processor->get_updated_html(); } elseif ( ! $block_supports_layout ) { // Ensure layout classnames are not injected if there is no layout support. return $block_content; } $fallback_layout = $block_type->supports['layout']['default'] ?? array(); if ( empty( $fallback_layout ) ) { $fallback_layout = $block_type->supports['__experimentalLayout']['default'] ?? array(); } $used_layout = $block['attrs']['layout'] ?? $fallback_layout; $class_names = array(); $layout_definitions = wp_get_layout_definitions(); // Set the correct layout type for blocks using legacy content width. if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) { $used_layout['type'] = 'constrained'; } $root_padding_aware_alignments = $global_settings['useRootPaddingAwareAlignments'] ?? false; if ( $root_padding_aware_alignments && isset( $used_layout['type'] ) && 'constrained' === $used_layout['type'] ) { $class_names[] = 'has-global-padding'; } /* * The following section was added to reintroduce a small set of layout classnames that were * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is * not intended to provide an extended set of classes to match all block layout attributes * here. */ if ( ! empty( $block['attrs']['layout']['orientation'] ) ) { $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] ); } if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) { $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] ); } if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) { $class_names[] = 'is-nowrap'; } // Get classname for layout type. if ( isset( $used_layout['type'] ) ) { $layout_classname = $layout_definitions[ $used_layout['type'] ]['className'] ?? ''; } else { $layout_classname = $layout_definitions['default']['className'] ?? ''; } if ( $layout_classname && is_string( $layout_classname ) ) { $class_names[] = sanitize_title( $layout_classname ); } /* * Only generate Layout styles if the theme has not opted-out. * Attribute-based Layout classnames are output in all cases. */ if ( ! current_theme_supports( 'disable-layout-styles' ) ) { $gap_value = wp_sanitize_block_gap_value( $style_attr['spacing']['blockGap'] ?? null ); $fallback_gap_value = $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? '0.5em'; $block_spacing = $style_attr['spacing'] ?? null; /* * If a block's block.json skips serialization for spacing or spacing.blockGap, * don't apply the user-defined value to the styles. */ $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); $block_gap = $global_settings['spacing']['blockGap'] ?? null; $has_block_gap_support = isset( $block_gap ); // Get default blockGap value from global styles for use in layouts like grid. // Check style variation first, then block-specific styles, then fall back to root styles. $block_name = $block['blockName'] ?? ''; if ( null === $global_styles ) { $global_styles = wp_get_global_styles(); } // Check if the block has an active style variation with a blockGap value. // Only check the registry if the className contains a variation class to avoid unnecessary lookups. $variation_block_gap_value = null; $block_class_name = is_string( $block['attrs']['className'] ?? null ) ? $block['attrs']['className'] : ''; if ( $block_class_name && str_contains( $block_class_name, 'is-style-' ) && $block_name ) { $styles_registry = WP_Block_Styles_Registry::get_instance(); $registered_styles = $styles_registry->get_registered_styles_for_block( $block_name ); $variation_name = wp_get_block_style_variation_name_from_registered_style( $block_class_name, $registered_styles ); if ( $variation_name ) { $variation_block_gap_value = $global_styles['blocks'][ $block_name ]['variations'][ $variation_name ]['spacing']['blockGap'] ?? null; } } $global_block_gap_value = $variation_block_gap_value ?? $global_styles['blocks'][ $block_name ]['spacing']['blockGap'] ?? $global_styles['spacing']['blockGap'] ?? null; if ( null !== $global_block_gap_value ) { $fallback_gap_value = $global_block_gap_value; } $container_class_hash_input = array( $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing, ); foreach ( array_keys( $responsive_media_queries ) as $breakpoint ) { $viewport_style = $style_attr[ $breakpoint ] ?? null; if ( ! is_array( $viewport_style ) ) { continue; } $viewport_container_layout = wp_get_layout_container_values( $viewport_style['layout'] ?? null ); if ( ! empty( $viewport_container_layout ) ) { $container_class_hash_input[] = array( 'breakpoint' => $breakpoint, 'layout' => $viewport_container_layout, ); } if ( isset( $viewport_style['spacing']['blockGap'] ) ) { $container_class_hash_input[] = array( 'breakpoint' => $breakpoint, 'blockGap' => wp_sanitize_block_gap_value( $viewport_style['spacing']['blockGap'] ), ); } } /* * Generates a unique ID based on all the data required to obtain the * corresponding layout style. Keeps the CSS class names the same * even for different blocks on different places, as long as they have * the same layout definition. Makes the CSS class names stable across * paginations for features like the enhanced pagination of the Query block. */ $container_class = wp_unique_id_from_values( $container_class_hash_input, 'wp-container-' . sanitize_title( $block['blockName'] ) . '-is-layout-' ); $style = wp_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value, $block_spacing ); /* * Emit responsive container layout styles using the same $container_class * selector as the base layout so they target the inner block wrapper. */ foreach ( $responsive_media_queries as $breakpoint => $media_query ) { $viewport_style = $style_attr[ $breakpoint ] ?? null; if ( ! is_array( $viewport_style ) ) { continue; } $viewport_container_layout = wp_get_layout_container_values( $viewport_style['layout'] ?? null ); $has_viewport_layout = ! empty( $viewport_container_layout ); $has_viewport_block_gap = isset( $viewport_style['spacing']['blockGap'] ); if ( ! $has_viewport_layout && ! $has_viewport_block_gap ) { continue; } $viewport_gap_value = $has_viewport_block_gap ? wp_sanitize_block_gap_value( $viewport_style['spacing']['blockGap'] ) : $gap_value; $viewport_block_spacing = is_array( $viewport_style['spacing'] ?? null ) ? array_replace( is_array( $block_spacing ) ? $block_spacing : array(), $viewport_style['spacing'] ) : $block_spacing; $viewport_styles = wp_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $viewport_gap_value, $should_skip_gap_serialization, $fallback_gap_value, $viewport_block_spacing, array( 'rules_group' => $media_query, 'viewport_overrides' => $viewport_container_layout, 'has_block_gap_override' => $has_viewport_block_gap, ) ); if ( ! empty( $viewport_styles ) && ! in_array( $container_class, $class_names, true ) ) { $class_names[] = $container_class; } } // Only add container class and enqueue block support styles if unique styles were generated. if ( ! empty( $style ) ) { $class_names[] = $container_class; } } // Add combined layout and block classname for global styles to hook onto. $split_block_name = explode( '/', $block['blockName'] ); $full_block_name = 'core' === $split_block_name[0] ? end( $split_block_name ) : implode( '-', $split_block_name ); $class_names[] = 'wp-block-' . $full_block_name . '-' . $layout_classname; // Add classes to the outermost HTML tag if necessary. if ( ! empty( $outer_class_names ) ) { foreach ( $outer_class_names as $outer_class_name ) { $processor->add_class( $outer_class_name ); } } /** * Attempts to refer to the inner-block wrapping element by its class attribute. * * When examining a block's inner content, if a block has inner blocks, then * the first content item will likely be a text (HTML) chunk immediately * preceding the inner blocks. The last HTML tag in that chunk would then be * an opening tag for an element that wraps the inner blocks. * * There's no reliable way to associate this wrapper in $block_content because * it may have changed during the rendering pipeline (as inner contents is * provided before rendering) and through previous filters. In many cases, * however, the `class` attribute will be a good-enough identifier, so this * code finds the last tag in that chunk and stores the `class` attribute * so that it can be used later when working through the rendered block output * to identify the wrapping element and add the remaining class names to it. * * It's also possible that no inner block wrapper even exists. If that's the * case this code could apply the class names to an invalid element. * * Example: * * $block['innerBlocks'] = array( $list_item ); * $block['innerContent'] = array( '' ); * * // After rendering, the initial contents may have been modified by other renderers or filters. * $block_content = << *
It's a list!
* * HTML; * * Although it is possible that the original block-wrapper classes are changed in $block_content * from how they appear in $block['innerContent'], it's likely that the original class attributes * are still present in the wrapper as they are in this example. Frequently, additional classes * will also be present; rarely should classes be removed. * * @todo Find a better way to match the first inner block. If it's possible to identify where the * first inner block starts, then it will be possible to find the last tag before it starts * and then that tag, if an opening tag, can be solidly identified as a wrapping element. * Can some unique value or class or ID be added to the inner blocks when they process * so that they can be extracted here safely without guessing? Can the block rendering function * return information about where the rendered inner blocks start? * * @var string|null */ $inner_block_wrapper_classes = null; $first_chunk = $block['innerContent'][0] ?? null; if ( is_string( $first_chunk ) && count( $block['innerContent'] ) > 1 ) { $first_chunk_processor = new WP_HTML_Tag_Processor( $first_chunk ); /* * Use a stack to track open elements as tags are visited. Void elements * (those without a matching closing tag) are excluded so they don't * accumulate on the stack. At the end of the chunk, every element still * on the stack is unclosed — meaning its closing tag lives in a later * innerContent entry alongside the inner blocks, which makes it the * inner-block container. Elements that open and close within this chunk * are siblings that precede the inner blocks and should be ignored. * The last unclosed element with a class attribute is the best candidate * for the inner-block wrapper. */ $tag_stack = array(); while ( $first_chunk_processor->next_tag( array( 'tag_closers' => 'visit' ) ) ) { if ( $first_chunk_processor->is_tag_closer() ) { array_pop( $tag_stack ); } elseif ( ! WP_HTML_Processor::is_void( $first_chunk_processor->get_tag() ) ) { $tag_stack[] = $first_chunk_processor->get_attribute( 'class' ); } } foreach ( array_reverse( $tag_stack ) as $class_attribute ) { if ( is_string( $class_attribute ) && ! empty( $class_attribute ) ) { $inner_block_wrapper_classes = $class_attribute; break; } } } /* * If necessary, advance to what is likely to be an inner block wrapper tag. * * This advances until it finds the first tag containing the original class * attribute from above. If none is found it will scan to the end of the block * and fail to add any class names. * * If there is no block wrapper it won't advance at all, in which case the * class names will be added to the first and outermost tag of the block. * For cases where this outermost tag is the only tag surrounding inner * blocks then the outer wrapper and inner wrapper are the same. */ do { if ( ! $inner_block_wrapper_classes ) { break; } $class_attribute = $processor->get_attribute( 'class' ); if ( is_string( $class_attribute ) && str_contains( $class_attribute, $inner_block_wrapper_classes ) ) { break; } } while ( $processor->next_tag() ); // Add the remaining class names. foreach ( $class_names as $class_name ) { $processor->add_class( $class_name ); } return $processor->get_updated_html(); } /** * Check if the parent block exists and if it has a layout attribute. * If it does, add the parent layout to the parsed block * * @since 6.6.0 * @access private * * @param array $parsed_block The parsed block. * @param array $source_block The source block. * @param WP_Block $parent_block The parent block. * @return array The parsed block with parent layout attribute if it exists. */ function wp_add_parent_layout_to_parsed_block( $parsed_block, $source_block, $parent_block ) { if ( $parent_block && isset( $parent_block->parsed_block['attrs']['layout'] ) ) { $parsed_block['parentLayout'] = $parent_block->parsed_block['attrs']['layout']; } return $parsed_block; } add_filter( 'render_block_data', 'wp_add_parent_layout_to_parsed_block', 10, 3 ); // Register the block support. WP_Block_Supports::get_instance()->register( 'layout', array( 'register_attribute' => 'wp_register_layout_support', ) ); add_filter( 'render_block', 'wp_render_layout_support_flag', 10, 2 ); /** * For themes without theme.json file, make sure * to restore the inner div for the group block * to avoid breaking styles relying on that div. * * @since 5.8.0 * @since 6.6.1 Removed inner container from Grid variations. * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_restore_group_inner_container( $block_content, $block ) { $tag_name = $block['attrs']['tagName'] ?? 'div'; $group_with_inner_container_regex = sprintf( '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/U', preg_quote( $tag_name, '/' ) ); if ( wp_theme_has_theme_json() || 1 === preg_match( $group_with_inner_container_regex, $block_content ) || ( isset( $block['attrs']['layout']['type'] ) && ( 'flex' === $block['attrs']['layout']['type'] || 'grid' === $block['attrs']['layout']['type'] ) ) ) { return $block_content; } /* * This filter runs after the layout classnames have been added to the block, so they * have to be removed from the outer wrapper and then added to the inner. */ $layout_classes = array(); $processor = new WP_HTML_Tag_Processor( $block_content ); if ( $processor->next_tag( array( 'class_name' => 'wp-block-group' ) ) ) { foreach ( $processor->class_list() as $class_name ) { if ( str_contains( $class_name, 'is-layout-' ) ) { $layout_classes[] = $class_name; $processor->remove_class( $class_name ); } } } $content_without_layout_classes = $processor->get_updated_html(); $replace_regex = sprintf( '/(^\s*<%1$s\b[^>]*wp-block-group[^>]*>)(.*)(<\/%1$s>\s*$)/ms', preg_quote( $tag_name, '/' ) ); $updated_content = preg_replace_callback( $replace_regex, static function ( $matches ) { return $matches[1] . '
' . $matches[2] . '
' . $matches[3]; }, $content_without_layout_classes ); // Add layout classes to inner wrapper. if ( ! empty( $layout_classes ) ) { $processor = new WP_HTML_Tag_Processor( $updated_content ); if ( $processor->next_tag( array( 'class_name' => 'wp-block-group__inner-container' ) ) ) { foreach ( $layout_classes as $class_name ) { $processor->add_class( $class_name ); } } $updated_content = $processor->get_updated_html(); } return $updated_content; } add_filter( 'render_block_core/group', 'wp_restore_group_inner_container', 10, 2 ); /** * For themes without theme.json file, make sure * to restore the outer div for the aligned image block * to avoid breaking styles relying on that div. * * @since 6.0.0 * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_restore_image_outer_container( $block_content, $block ) { if ( wp_theme_has_theme_json() ) { return $block_content; } $figure_processor = new WP_HTML_Tag_Processor( $block_content ); if ( ! $figure_processor->next_tag( 'FIGURE' ) || ! $figure_processor->has_class( 'wp-block-image' ) || ! ( $figure_processor->has_class( 'alignleft' ) || $figure_processor->has_class( 'aligncenter' ) || $figure_processor->has_class( 'alignright' ) ) ) { return $block_content; } /* * The next section of code wraps the existing figure in a new DIV element. * While doing it, it needs to transfer the layout and the additional CSS * class names from the original figure upward to the wrapper. * * Example: * * // From this… * *
… * * // To this… *
… */ $wrapper_processor = new WP_HTML_Tag_Processor( '
' ); $wrapper_processor->next_token(); $wrapper_processor->set_attribute( 'class', is_string( $block['attrs']['className'] ?? null ) ? "wp-block-image {$block['attrs']['className']}" : 'wp-block-image' ); // And remove them from the existing content; it has been transferred upward. $figure_processor->remove_class( 'wp-block-image' ); foreach ( $wrapper_processor->class_list() as $class_name ) { $figure_processor->remove_class( $class_name ); } return "{$wrapper_processor->get_updated_html()}{$figure_processor->get_updated_html()}
"; } add_filter( 'render_block_core/image', 'wp_restore_image_outer_container', 10, 2 ); : Datenschutz

Datenschutz

Datenschutzerklärung

Verantwortliche Stelle im Sinne der Datenschutzgesetze ist:

Verantwortlicher

Turnverein 1868 e.V. Bad Orb
Bahnhofstraße 7
63619 Bad Orb
Telefon: 06052 / 1414

Vertreten durch:
Lara Bangert – 1. Vorsitzender
Petra Joffroy – 2. Vorsitzender
Richard Labude – 2. Vorsitzender

Cookies

Wie viele andere Webseiten verwenden wir auch so genannte „Cookies“. Cookies sind kleine Textdateien, die von einem Webseitenserver auf Ihre Festplatte übertragen werden. Hierdurch erhalten wir automatisch bestimmte Daten wie z. B. IP-Adresse, verwendeter Browser, Betriebssystem über Ihren Computer und Ihre Verbindung zum Internet.

Cookies können nicht verwendet werden, um Programme zu starten oder Viren auf einen Computer zu übertragen. Anhand der in Cookies enthaltenen Informationen können wir Ihnen die Navigation erleichtern und die korrekte Anzeige unserer Webseiten ermöglichen.

In keinem Fall werden die von uns erfassten Daten an Dritte weitergegeben oder ohne Ihre Einwilligung eine Verknüpfung mit personenbezogenen Daten hergestellt.

Natürlich können Sie unsere Website grundsätzlich auch ohne Cookies betrachten. Internet-Browser sind regelmäßig so eingestellt, dass sie Cookies akzeptieren. Sie können die Verwendung von Cookies jederzeit über die Einstellungen Ihres Browsers deaktivieren. Bitte verwenden Sie die Hilfefunktionen Ihres Internetbrowsers, um zu erfahren, wie Sie diese Einstellungen ändern können. Bitte beachten Sie, dass einzelne Funktionen unserer Website möglicherweise nicht funktionieren, wenn Sie die Verwendung von Cookies deaktiviert haben.

SSL-Verschlüsselung

Um die Sicherheit Ihrer Daten bei der Übertragung zu schützen, verwenden wir dem aktuellen Stand der Technik entsprechende Verschlüsselungsverfahren (z. B. SSL) über HTTPS.

Kommentarfunktion

Wenn Nutzer Kommentare im Blog hinterlassen, werden neben diesen Angaben auch der Zeitpunkt ihrer Erstellung und der zuvor durch den Websitebesucher gewählte Nutzername gespeichert. Dies dient unserer Sicherheit, da wir für widerrechtliche Inhalte auf unserer Webseite belangt werden können, auch wenn diese durch Benutzer erstellt wurden.

Kontaktformular

Treten Sie per E-Mail oder Kontaktformular mit uns in Kontakt, werden die von Ihnen gemachten Angaben zum Zwecke der Bearbeitung der Anfrage sowie für mögliche Anschlussfragen gespeichert.

Löschung bzw. Sperrung der Daten

Wir halten uns an die Grundsätze der Datenvermeidung und Datensparsamkeit. Wir speichern Ihre personenbezogenen Daten daher nur so lange, wie dies zur Erreichung der hier genannten Zwecke erforderlich ist oder wie es die vom Gesetzgeber vorgesehenen vielfältigen Speicherfristen vorsehen. Nach Fortfall des jeweiligen Zweckes bzw. Ablauf dieser Fristen werden die entsprechenden Daten routinemäßig und entsprechend den gesetzlichen Vorschriften gesperrt oder gelöscht.

Verwendung von Google Maps

Diese Webseite verwendet Google Maps API, um geographische Informationen visuell darzustellen. Bei der Nutzung von Google Maps werden von Google auch Daten über die Nutzung der Kartenfunktionen durch Besucher erhoben, verarbeitet und genutzt. Nähere Informationen über die Datenverarbeitung durch Google können Sie den Google-Datenschutzhinweisen entnehmen. Dort können Sie im Datenschutzcenter auch Ihre persönlichen Datenschutz-Einstellungen verändern.

Ausführliche Anleitungen zur Verwaltung der eigenen Daten im Zusammenhang mit Google-Produkten finden Sie hier.

Eingebettete YouTube-Videos

Auf einigen unserer Webseiten betten wir Youtube-Videos ein. Betreiber der entsprechenden Plugins ist die YouTube, LLC, 901 Cherry Ave., San Bruno, CA 94066, USA. Wenn Sie eine Seite mit dem YouTube-Plugin besuchen, wird eine Verbindung zu Servern von Youtube hergestellt. Dabei wird Youtube mitgeteilt, welche Seiten Sie besuchen. Wenn Sie in Ihrem Youtube-Account eingeloggt sind, kann Youtube Ihr Surfverhalten Ihnen persönlich zuzuordnen. Dies verhindern Sie, indem Sie sich vorher aus Ihrem Youtube-Account ausloggen.

Wird ein Youtube-Video gestartet, setzt der Anbieter Cookies ein, die Hinweise über das Nutzerverhalten sammeln.

Wer das Speichern von Cookies für das Google-Ad-Programm deaktiviert hat, wird auch beim Anschauen von Youtube-Videos mit keinen solchen Cookies rechnen müssen. Youtube legt aber auch in anderen Cookies nicht-personenbezogene Nutzungsinformationen ab. Möchten Sie dies verhindern, so müssen Sie das Speichern von Cookies im Browser blockieren.

Weitere Informationen zum Datenschutz bei „Youtube“ finden Sie in der Datenschutzerklärung des Anbieters unter: https://www.google.de/intl/de/policies/privacy/

Ihre Rechte auf Auskunft, Berichtigung, Sperre, Löschung und Widerspruch

Sie haben das Recht, jederzeit Auskunft über Ihre bei uns gespeicherten personenbezogenen Daten zu erhalten. Ebenso haben Sie das Recht auf Berichtigung, Sperrung oder, abgesehen von der vorgeschriebenen Datenspeicherung zur Geschäftsabwicklung, Löschung Ihrer personenbezogenen Daten. Bitte wenden Sie sich dazu an unseren Datenschutzbeauftragten. Die Kontaktdaten finden Sie ganz unten.

Damit eine Sperre von Daten jederzeit berücksichtigt werden kann, müssen diese Daten zu Kontrollzwecken in einer Sperrdatei vorgehalten werden. Sie können auch die Löschung der Daten verlangen, soweit keine gesetzliche Archivierungsverpflichtung besteht. Soweit eine solche Verpflichtung besteht, sperren wir Ihre Daten auf Wunsch.

Sie können Änderungen oder den Widerruf einer Einwilligung durch entsprechende Mitteilung an uns mit Wirkung für die Zukunft vornehmen.

Änderung unserer Datenschutzbestimmungen

Wir behalten uns vor, diese Datenschutzerklärung gelegentlich anzupassen, damit sie stets den aktuellen rechtlichen Anforderungen entspricht oder um Änderungen unserer Leistungen in der Datenschutzerklärung umzusetzen, z. B. bei der Einführung neuer Services. Für Ihren erneuten Besuch gilt dann die neue Datenschutzerklärung.

Fragen an den Datenschutzbeauftragten

Wenn Sie Fragen zum Datenschutz haben, schreiben Sie uns bitte eine E-Mail oder wenden Sie sich direkt an unseren Datenschutzbeauftragten über das Kontaktformular:

Die Datenschutzerklärung wurde mit dem Datenschutzerklärungs-Generator der activeMind AG erstellt.