$block ) {
if ( ! is_object( $block ) && is_array( $block ) && isset( $block['blockName'] ) ) {
if ( 'generateblocks/grid' === $block['blockName'] ) {
$data['grid'][] = $block['attrs'];
$depth++;
$data[ 'tempGridId-' . $depth ] = $block['attrs']['uniqueId'];
}
if ( 'generateblocks/container' === $block['blockName'] ) {
if ( isset( $block['attrs']['isGrid'] ) && $block['attrs']['isGrid'] && isset( $data[ 'tempGridId-' . $depth ] ) ) {
$block['attrs']['gridId'] = $data[ 'tempGridId-' . $depth ];
}
$data['container'][] = $block['attrs'];
}
if ( 'generateblocks/headline' === $block['blockName'] ) {
if ( isset( $block['innerHTML'] ) ) {
if ( strpos( trim( $block['innerHTML'] ), '
sanitize_html_class( $context ),
);
$attributes = wp_parse_args( $attributes, $defaults );
// Contextual filter.
return apply_filters( "generateblocks_attr_{$context}", $attributes, $settings, $context, $block );
}
/**
* Generate our SVG shape dividers.
*
* @since 1.2.0
*/
function generateblocks_get_svg_shapes() {
return apply_filters(
'generateblocks_svg_shapes',
array(
'gb-waves' => array(
'group' => esc_attr__( 'Waves', 'generateblocks' ),
'svgs' => array(
'gb-waves-1' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '1' ),
'icon' => '
',
),
'gb-waves-2' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '2' ),
'icon' => '
',
),
'gb-waves-3' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '3' ),
'icon' => '
',
),
'gb-waves-4' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '4' ),
'icon' => '
',
),
'gb-waves-5' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '5' ),
'icon' => '
',
),
'gb-waves-6' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '6' ),
'icon' => '
',
),
'gb-waves-7' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '7' ),
'icon' => '
',
),
'gb-waves-8' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Wave %s', 'generateblocks' ), '8' ),
'icon' => '
',
),
),
),
'gb-angles' => array(
'group' => esc_attr__( 'Angles', 'generateblocks' ),
'svgs' => array(
'gb-angle-1' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Angle %s', 'generateblocks' ), '1' ),
'icon' => '
',
),
),
),
'gb-curves' => array(
'group' => esc_attr__( 'Curves', 'generateblocks' ),
'svgs' => array(
'gb-curve-1' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '1' ),
'icon' => '
',
),
'gb-curve-2' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '2' ),
'icon' => '
',
),
'gb-curve-3' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '3' ),
'icon' => '
',
),
'gb-curve-4' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Curve %s', 'generateblocks' ), '4' ),
'icon' => '
',
),
),
),
'gb-triangles' => array(
'group' => esc_attr__( 'Triangles', 'generateblocks' ),
'svgs' => array(
'gb-triangle-1' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '1' ),
'icon' => '
',
),
'gb-triangle-2' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '2' ),
'icon' => '
',
),
'gb-triangle-3' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '3' ),
'icon' => '
',
),
'gb-triangle-4' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '4' ),
'icon' => '
',
),
'gb-triangle-5' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '5' ),
'icon' => '
',
),
'gb-triangle-6' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '6' ),
'icon' => '
',
),
'gb-triangle-7' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '7' ),
'icon' => '
',
),
'gb-triangle-8' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '8' ),
'icon' => '
',
),
'gb-triangle-9' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '9' ),
'icon' => '
',
),
'gb-triangle-10' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '10' ),
'icon' => '
',
),
'gb-triangle-11' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '11' ),
'icon' => '
',
),
'gb-triangle-12' => array(
/* translators: Shape number */
'label' => sprintf( __( 'Triangle %s', 'generateblocks' ), '12' ),
'icon' => '
',
),
),
),
)
);
}
/**
* Search an array to check if a key has a value.
*
* @since 1.5.0
* @param string $setting The setting to check.
* @param array $data The array to search.
*/
function generateblocks_block_has_value( $setting, $data ) {
foreach ( (array) $data as $key => $val ) {
if ( isset( $val[ $setting ] ) && ( $val[ $setting ] || 0 === $val[ $setting ] ) ) {
return true;
}
}
return null;
}
/**
* Given an array it will change keys based on the map.
*
* @param array $arr The array to check.
* @param array $keyMap The array to map.
*
* @return array|false
*
* @since 1.5.0
*/
function generateblocks_map_array_keys( $arr = array(), $keyMap = array() ) {
return array_combine(
array_map(
function( $key ) use ( $keyMap ) {
return isset( $keyMap[ $key ] ) ? $keyMap[ $key ] : $key;
},
array_keys( $arr )
),
array_values( $arr )
);
}
/**
* Checks if the date is correctly formatted
*
* @param string $date The date to validate.
* @param string $format The allowed format.
*
* @return bool
*/
function generateblocks_is_valid_date( $date, $format = 'Y-m-d\TH:i:s' ) {
$dateTime = DateTime::createFromFormat( $format, $date );
return ( $dateTime && $dateTime->format( $format ) === $date );
}
/**
* Modifies the markup of images in provided content.
*
* @param string $content The content to modify.
* @param array $attributes The block attributes.
*
* @since 1.5.0
*/
function generateblocks_filter_images( $content, $attributes ) {
// Bail early if not using WP 5.5.
if ( ! function_exists( 'wp_img_tag_add_width_and_height_attr' ) ) {
return $content;
}
if ( ! empty( $attributes['mediaId'] ) ) {
// Add 'width' and 'height' attributes if applicable.
if ( false === strpos( $content, ' width=' ) && false === strpos( $content, ' height=' ) ) {
$content = wp_img_tag_add_width_and_height_attr( $content, '', $attributes['mediaId'] );
}
// Add 'srcset' and 'sizes' attributes if applicable.
if ( false === strpos( $content, ' srcset=' ) ) {
$content = wp_img_tag_add_srcset_and_sizes_attr( $content, '', $attributes['mediaId'] );
}
}
// Add 'loading' attribute if applicable.
if ( wp_lazy_loading_enabled( 'img', '' ) && false === strpos( $content, ' loading=' ) ) {
$content = function_exists( 'wp_img_tag_add_loading_optimization_attrs' )
? wp_img_tag_add_loading_optimization_attrs( $content, '' )
: wp_img_tag_add_loading_attr( $content, '' );
}
return $content;
}
/**
* Compile our CSS based on our CSS data.
*
* @since 1.6.0
* @param array $manual_data CSS data input directly to the function.
*/
function generateblocks_get_compiled_css( $manual_data = [] ) {
$data = apply_filters( 'generateblocks_css_data', [] );
// Allows us to input manual data if necessary.
if ( count( (array) $manual_data ) > 0 ) {
$data = $manual_data;
}
$css = '';
if ( ! empty( $data['main'] ) ) {
$css .= $data['main'];
}
if ( ! empty( $data['desktop'] ) ) {
$css .= sprintf(
'@media %1$s {%2$s}',
generateblocks_get_media_query( 'desktop' ),
$data['desktop']
);
}
if ( ! empty( $data['tablet'] ) ) {
$css .= sprintf(
'@media %1$s {%2$s}',
generateblocks_get_media_query( 'tablet' ),
$data['tablet']
);
}
if ( ! empty( $data['tablet_only'] ) ) {
$css .= sprintf(
'@media %1$s {%2$s}',
generateblocks_get_media_query( 'tablet_only' ),
$data['tablet_only']
);
}
if ( ! empty( $data['mobile'] ) ) {
$css .= sprintf(
'@media %1$s {%2$s}',
generateblocks_get_media_query( 'mobile' ),
$data['mobile']
);
}
return $css;
}
/**
* This is a helper function that groups our static CSS into device-specific groups.
*
* @param array $existing_data An array of existing data to add to.
* @param array $new_data The new data we wish to group.
*
* @since 1.6.0
*/
function generateblocks_group_css_data( $existing_data = [], $new_data = [] ) {
$existing_data = wp_parse_args(
$existing_data,
[
'main' => '',
'desktop' => '',
'tablet' => '',
'tablet_only' => '',
'mobile' => '',
]
);
$existing_data['main'] .= generateblocks_get_parsed_css( $new_data['main'] );
$existing_data['desktop'] .= generateblocks_get_parsed_css( $new_data['desktop'] );
$existing_data['tablet'] .= generateblocks_get_parsed_css( $new_data['tablet'] );
$existing_data['tablet_only'] .= generateblocks_get_parsed_css( $new_data['tablet_only'] );
$existing_data['mobile'] .= generateblocks_get_parsed_css( $new_data['mobile'] );
return $existing_data;
}
/**
* Turn our CSS array into plain CSS.
*
* @since 1.0
* @param array $data Our CSS data.
*/
function generateblocks_get_parsed_css( $data ) {
$output = '';
foreach ( $data as $selector => $properties ) {
if ( ! count( $properties ) ) {
continue;
}
$temporary_output = $selector . '{';
$elements_added = 0;
foreach ( $properties as $key => $value ) {
if ( empty( $value ) ) {
continue;
}
$elements_added++;
$temporary_output .= $value;
}
$temporary_output .= '}';
if ( $elements_added > 0 ) {
$output .= $temporary_output;
}
}
return $output;
}
/**
* Build the CSS from our block attributes.
*
* @since 0.1
* @param string $content The content we're looking through.
* @param string $store_block_id_only Store the found block IDs instead of adding CSS.
*
* @return string The dynamic CSS.
*/
function generateblocks_get_dynamic_css( $content = '', $store_block_id_only = false ) {
if ( ! $content ) {
$content = generateblocks_get_parsed_content();
}
$data = generateblocks_get_block_data( $content );
if ( empty( $data ) ) {
return;
}
$blocks = apply_filters(
'generateblocks_dynamic_css_blocks',
[
'text' => 'GenerateBlocks_Block_Text',
'element' => 'GenerateBlocks_Block_Element',
'media' => 'GenerateBlocks_Block_Media',
'shape' => 'GenerateBlocks_Block_Shape',
'query' => 'GenerateBlocks_Block_Query',
'looper' => 'GenerateBlocks_Block_Looper',
'query-page-numbers' => 'GenerateBlocks_Block_Query_Page_Numbers',
'loop-item' => 'GenerateBlocks_Block_Loop_Item',
]
);
$legacy_blocks = [
'grid' => 'GenerateBlocks_Block_Grid',
'container' => 'GenerateBlocks_Block_Container',
'button-container' => 'GenerateBlocks_Block_Button_Container',
'button' => 'GenerateBlocks_Block_Button',
'headline' => 'GenerateBlocks_Block_Headline',
'image' => 'GenerateBlocks_Block_Image',
];
$all_blocks = array_merge(
$blocks,
$legacy_blocks
);
foreach ( $data as $name => $blockData ) {
if ( isset( $all_blocks[ $name ] ) ) {
if ( empty( $blockData ) ) {
continue;
}
foreach ( $blockData as $attributes ) {
$id = $attributes['uniqueId'] ?? '';
if ( ! $id ) {
continue;
}
do_action(
'generateblocks_process_block_css',
[
'block_short_name' => $name,
'attributes' => $attributes,
'current_filter' => current_filter(),
]
);
if (
isset( $blocks[ $name ] ) &&
is_callable( [ $blocks[ $name ], 'enqueue_assets' ] )
) {
$blocks[ $name ]::enqueue_assets();
}
if ( $store_block_id_only ) {
$all_blocks[ $name ]::store_block_id( $id );
} elseif ( ! $all_blocks[ $name ]::block_id_exists( $id ) ) {
// Generate CSS for our block.
if ( isset( $blocks[ $name ] ) ) {
$css = $blocks[ $name ]::get_css( $attributes );
$css = wp_strip_all_tags( $css );
add_filter(
'generateblocks_css_output',
function( $output ) use ( $css ) {
return $output .= wp_strip_all_tags( $css );
}
);
}
// Generate CSS for our legacy block.
if ( isset( $legacy_blocks[ $name ] ) ) {
if ( is_callable( [ $legacy_blocks[ $name ], 'get_css_data' ] ) ) {
generateblocks_add_to_css_data(
$legacy_blocks[ $name ]::get_css_data( $attributes )
);
}
}
}
}
}
}
}
/**
* Print our CSS for each block.
*
* @since 0.1
*/
function generateblocks_get_frontend_block_css() {
return apply_filters( 'generateblocks_css_output', generateblocks_get_compiled_css() );
}
/**
* Add block CSS to our pool of generated CSS.
*
* @since 1.6.0
* @param array $data Our CSS data.
*/
function generateblocks_add_to_css_data( $data ) {
add_filter(
'generateblocks_css_data',
function( $css_data ) use ( $data ) {
return generateblocks_group_css_data( $css_data, $data );
}
);
}
/**
* Maybe add block CSS if it hasn't already been added for this block.
*
* @since 1.6.0
* @param string $content Our block content.
* @param array $data Block data.
*/
function generateblocks_maybe_add_block_css( $content = '', $data = [] ) {
$legacy_blocks = [
'grid' => 'GenerateBlocks_Block_Grid',
'container' => 'GenerateBlocks_Block_Container',
'button-container' => 'GenerateBlocks_Block_Button_Container',
'button' => 'GenerateBlocks_Block_Button',
'headline' => 'GenerateBlocks_Block_Headline',
'image' => 'GenerateBlocks_Block_Image',
];
if ( in_array( $data['class_name'], $legacy_blocks ) ) {
return generateblocks_maybe_add_legacy_block_css( $content, $data );
}
$inline_style_override = apply_filters(
'generateblocks_do_inline_styles',
false,
[
'content' => $content,
'data' => $data,
]
);
$id = $data['attributes']['uniqueId'] ?? '';
if ( ! $id ) {
return $content;
}
if ( in_array( $id, $data['block_ids'] ) && ! $inline_style_override ) {
return $content;
}
if ( ! GenerateBlocks_Enqueue_CSS::can_enqueue() && ! $inline_style_override ) {
return $content;
}
$css = $data['class_name']::get_css( $data['attributes'] );
if ( ! $css ) {
return $content;
}
if ( did_action( 'wp_head' ) || $inline_style_override ) {
// Add inline ',
wp_strip_all_tags( $css )
) . $content;
} else {
// Add our CSS to the pool of existing CSS in wp_head.
add_filter(
'generateblocks_css_output',
function( $output ) use ( $css ) {
return $output .= wp_strip_all_tags( $css );
}
);
}
return $content;
}
/**
* Maybe add block CSS if it hasn't already been added for this block.
*
* @since 1.6.0
* @param string $content Our block content.
* @param array $data Block data.
*/
function generateblocks_maybe_add_legacy_block_css( $content = '', $data = [] ) {
$inline_style_override = apply_filters(
'generateblocks_do_inline_styles',
false,
[
'content' => $content,
'data' => $data,
]
);
if (
isset( $data['attributes']['uniqueId'] ) &&
(
! in_array( $data['attributes']['uniqueId'], $data['block_ids'] ) ||
$inline_style_override
)
) {
// Don't try to print CSS for the Query Loop block.
if ( isset( $data['attributes']['query'] ) ) {
return $content;
}
if ( ! GenerateBlocks_Enqueue_CSS::can_enqueue() && ! $inline_style_override ) {
return $content;
}
$css_data = is_callable( [ $data['class_name'], 'get_css_data' ] )
? $data['class_name']::get_css_data( $data['attributes'] )
: false;
if ( ! $css_data ) {
return $content;
}
if ( did_action( 'wp_head' ) || $inline_style_override ) {
// Add inline ',
wp_strip_all_tags( $compiled_css )
) . $content;
}
} else {
// Add our CSS to the pool of existing CSS in wp_head.
generateblocks_add_to_css_data( $css_data );
}
}
return $content;
}
/**
* Get our default Container block width.
*
* @since 1.7.0
*/
function generateblocks_get_global_container_width() {
return apply_filters(
'generateblocks_global_container_width',
function_exists( 'generate_get_option' )
? generate_get_option( 'container_width' ) . 'px'
: generateblocks_get_option( 'container_width' ) . 'px'
);
}
/**
* Add our Layout component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_layout_css( $css, $settings, $device = '' ) {
if ( ! empty( $settings['useInnerContainer'] ) ) {
return;
}
$options = [
'display' => 'display',
'flex-direction' => 'flexDirection',
'flex-wrap' => 'flexWrap',
'align-items' => 'alignItems',
'justify-content' => 'justifyContent',
'column-gap' => 'columnGap',
'row-gap' => 'rowGap',
'z-index' => 'zindex',
'position' => 'position',
'overflow-x' => 'overflowX',
'overflow-y' => 'overflowY',
];
foreach ( $options as $property => $option ) {
$value = isset( $settings[ $option . $device ] ) ? $settings[ $option . $device ] : '';
$css->add_property( $property, $value );
}
}
/**
* Add our Sizing component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_sizing_css( $css, $settings, $device = '' ) {
$options = [
'width' => 'width',
'height' => 'height',
'min-width' => 'minWidth',
'min-height' => 'minHeight',
'max-width' => 'maxWidth',
'max-height' => 'maxHeight',
];
if ( ! empty( $settings['useInnerContainer'] ) ) {
unset( $options['max-width'] );
}
if ( ! empty( $settings['isGrid'] ) ) {
unset( $options['width'] );
unset( $options['min-width'] );
unset( $options['max-width'] );
}
foreach ( $options as $property => $option ) {
$option_name = $option . $device;
$value = generateblocks_get_array_attribute_value( $option_name, $settings['sizing'] );
if ( 'max-width' === $property && ! empty( $settings['useGlobalMaxWidth'] ) && ! $device ) {
$value = generateblocks_get_global_container_width();
}
$css->add_property( $property, $value );
}
}
/**
* Add our Flex Child component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_flex_child_css( $css, $settings, $device = '' ) {
if ( ! empty( $settings['isGrid'] ) ) {
return;
}
$options = [
'flex-grow' => 'flexGrow',
'flex-shrink' => 'flexShrink',
'flex-basis' => 'flexBasis',
'order' => 'order',
];
foreach ( $options as $property => $option ) {
$value = isset( $settings[ $option . $device ] ) ? $settings[ $option . $device ] : '';
$css->add_property( $property, $value );
}
}
/**
* Add our Typography component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_typography_css( $css, $settings, $device = '' ) {
$options = [
'font-family' => 'fontFamily',
'font-size' => 'fontSize',
'line-height' => 'lineHeight',
'letter-spacing' => 'letterSpacing',
'font-weight' => 'fontWeight',
'text-transform' => 'textTransform',
'text-align' => 'textAlign',
];
foreach ( $options as $property => $option ) {
$option_name = $option . $device;
$value = generateblocks_get_array_attribute_value( $option_name, $settings['typography'] );
if ( 'fontFamily' === $option && $value && $settings['fontFamilyFallback'] ) {
$value .= ', ' . $settings['fontFamilyFallback'];
}
$css->add_property( $property, $value );
}
}
/**
* Add our Spacing component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_spacing_css( $css, $settings, $device = '' ) {
$padding_values = array_map(
function( $attribute ) use ( $device, $settings ) {
if ( isset( $settings['useInnerContainer'] ) && $settings['useInnerContainer'] ) {
return false;
}
return generateblocks_get_array_attribute_value( $attribute . $device, $settings['spacing'] );
},
[
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
]
);
$css->add_property(
'padding',
$padding_values
);
$margin_values = array_map(
function( $attribute ) use ( $device, $settings ) {
return generateblocks_get_array_attribute_value( $attribute . $device, $settings['spacing'] );
},
[
'marginTop',
'marginRight',
'marginBottom',
'marginLeft',
]
);
$css->add_property(
'margin',
$margin_values
);
}
/**
* Add our Borders component CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $device The device we're adding to.
*/
function generateblocks_add_border_css( $css, $settings, $device = '' ) {
$border_radius_values = array_map(
function( $attribute ) use ( $device, $settings ) {
return generateblocks_get_array_attribute_value( $attribute . $device, $settings['borders'] );
},
[
'borderTopLeftRadius',
'borderTopRightRadius',
'borderBottomRightRadius',
'borderBottomLeftRadius',
]
);
$css->add_property(
'border-radius',
$border_radius_values
);
$borders = [
'border-top' => [
'border-top-width' => 'borderTopWidth',
'border-top-style' => 'borderTopStyle',
'border-top-color' => 'borderTopColor',
],
'border-right' => [
'border-right-width' => 'borderRightWidth',
'border-right-style' => 'borderRightStyle',
'border-right-color' => 'borderRightColor',
],
'border-bottom' => [
'border-bottom-width' => 'borderBottomWidth',
'border-bottom-style' => 'borderBottomStyle',
'border-bottom-color' => 'borderBottomColor',
],
'border-left' => [
'border-left-width' => 'borderLeftWidth',
'border-left-style' => 'borderLeftStyle',
'border-left-color' => 'borderLeftColor',
],
];
$border_values = [];
foreach ( $borders as $property => $values ) {
foreach ( $values as $property_name => $value_name ) {
$value = generateblocks_get_array_attribute_value( $value_name . $device, $settings['borders'] );
if ( $value || is_numeric( $value ) ) {
$border_values[ $property ][ $property_name ] = $value;
}
}
}
if ( ! empty( $border_values ) ) {
$number_of_borders = count( (array) $border_values );
$all_equal = false;
if ( 4 === $number_of_borders ) {
$all_values = array_map(
function( $value ) {
return trim( implode( ' ', array_values( $value ) ) );
},
$border_values
);
$all_equal = 1 === count( array_unique( $all_values ) );
}
if ( $all_equal ) {
$css->add_property(
'border',
trim( implode( ' ', array_values( $border_values['border-top'] ) ) )
);
} else {
foreach ( $border_values as $shorthand_property => $values ) {
$number_of_values = count( (array) $values );
if ( 3 === $number_of_values ) {
// Use the shorthand property with all three values.
$css->add_property(
$shorthand_property,
trim( implode( ' ', array_values( $values ) ) )
);
} else {
foreach ( $values as $property => $value ) {
// Use the longhand property as we don't have all three values.
$css->add_property(
$property,
$value
);
}
}
}
}
}
}
/**
* Add border color CSS.
*
* @param object $css The CSS object to add to.
* @param array $settings Block settings.
* @param string $state The state we're adding to.
*/
function generateblocks_add_border_color_css( $css, $settings, $state = '' ) {
$colors = [
'border-top-color' => 'borderTopColor',
'border-right-color' => 'borderRightColor',
'border-bottom-color' => 'borderBottomColor',
'border-left-color' => 'borderLeftColor',
];
$color_values = [];
foreach ( $colors as $property => $value_name ) {
$value = generateblocks_get_array_attribute_value( $value_name . $state, $settings['borders'] );
if ( $value ) {
$color_values[ $state ][ $property ] = $value;
}
}
if ( isset( $color_values[ $state ] ) ) {
$number_of_colors = count( (array) $color_values[ $state ] );
$all_equal = 4 === $number_of_colors && 1 === count( array_unique( $color_values[ $state ] ) );
if ( $all_equal ) {
$first_color = array_values( $color_values[ $state ] )[0];
$css->add_property(
'border-color',
$first_color
);
} else {
foreach ( $color_values[ $state ] as $property => $value ) {
$css->add_property(
$property,
$value
);
}
}
}
}
/**
* Helper function to get an attribute value from an array.
*
* @param string $name The name of the attribute.
* @param array $array The array of attribute values.
*/
function generateblocks_get_array_attribute_value( $name, $array ) {
return isset( $array[ $name ] ) ? $array[ $name ] : '';
}
/**
* Return the CSS selector for a specific block.
*
* @param string $name The name of the block.
* @param array $attributes The block attributes.
*/
function generateblocks_get_css_selector( $name, $attributes ) {
$selector = '';
$id = $attributes['uniqueId'];
if ( 'button' === $name ) {
$selector = '.gb-button-' . $id;
}
if ( 'headline' === $name ) {
$selector = '.gb-headline-' . $id;
}
if ( 'container' === $name ) {
$selector = '.gb-container-' . $id;
}
return apply_filters(
'generateblocks_block_css_selector',
$selector,
$name,
$attributes
);
}
/**
* Determine whether we should add the :visited selector to links.
*
* @param string $name The block name.
* @param array $attributes The block attributes.
*/
function generateblocks_use_visited_selector( $name, $attributes ) {
$blockVersion = ! empty( $attributes['blockVersion'] ) ? $attributes['blockVersion'] : 1;
$use_visited_selector = false;
if ( ( 'button' === $name || 'container' === $name ) && $blockVersion < 3 ) {
$use_visited_selector = true;
}
if ( 'headline' === $name && $blockVersion < 2 ) {
$use_visited_selector = true;
}
return apply_filters(
'generateblocks_use_visited_selector',
$use_visited_selector,
$name,
$attributes
);
}
/**
* Returns the global $wp_filesystem with credentials set.
* Returns null in case of any errors.
*
* @return WP_Filesystem_Base|null
*/
function generateblocks_get_wp_filesystem() {
global $wp_filesystem;
$success = true;
// Initialize the file system if it has not been done yet.
if ( ! $wp_filesystem ) {
require_once ABSPATH . '/wp-admin/includes/file.php';
$constants = array(
'hostname' => 'FTP_HOST',
'username' => 'FTP_USER',
'password' => 'FTP_PASS',
'public_key' => 'FTP_PUBKEY',
'private_key' => 'FTP_PRIKEY',
);
$credentials = array();
// We provide credentials based on wp-config.php constants.
// Reference https://developer.wordpress.org/apis/wp-config-php/#wordpress-upgrade-constants.
foreach ( $constants as $key => $constant ) {
if ( defined( $constant ) ) {
$credentials[ $key ] = constant( $constant );
}
}
$success = WP_Filesystem( $credentials );
}
if ( ! $success || $wp_filesystem->errors->has_errors() ) {
return null;
}
return $wp_filesystem;
}
/**
* Add global defaults to our blocks.
*
* @since 1.7.1
* @param array $defaults The existing defaults.
*/
function generateblocks_with_global_defaults( $defaults ) {
$display = [
'display',
'flexDirection',
'flexWrap',
'alignItems',
'justifyContent',
'columnGap',
'rowGap',
'position',
'overflowX',
'overflowY',
'zindex',
];
$flex_child = [
'flexGrow',
'flexShrink',
'flexBasis',
'order',
];
$spacing = [
'marginTop',
'marginRight',
'marginBottom',
'marginLeft',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'borderSizeTop',
'borderSizeRight',
'borderSizeBottom',
'borderSizeLeft',
'borderRadiusTopRight',
'borderRadiusBottomRight',
'borderRadiusBottomLeft',
'borderRadiusTopLeft',
];
$options = array_merge(
$display,
$flex_child,
$spacing
);
foreach ( $options as $option ) {
$defaults[ $option ] = '';
$defaults[ $option . 'Tablet' ] = '';
$defaults[ $option . 'Mobile' ] = '';
}
// Spacing.
$defaults['spacing'] = [];
$defaults['marginUnit'] = 'px';
$defaults['paddingUnit'] = 'px';
$defaults['borderRadiusUnit'] = 'px';
// Sizing.
$defaults['sizing'] = [];
$defaults['useGlobalMaxWidth'] = false;
// Typography.
$defaults['typography'] = [];
// Icons.
$defaults['iconStyles'] = [];
// Borders.
$defaults['borders'] = [];
return $defaults;
}
/**
* Get the list of font families for our font family control.
*
* @since 1.8.0
* @return array List of grouped fonts.
*/
function generateblocks_get_font_family_list() {
return apply_filters(
'generateblocks_typography_font_family_list',
[
[
'label' => __( 'System Fonts', 'generateblocks' ),
'options' => [
[
'value' => 'Arial',
'label' => 'Arial',
],
[
'value' => 'Helvetica',
'label' => 'Helvetica',
],
[
'value' => 'Times New Roman',
'label' => 'Times New Roman',
],
[
'value' => 'Georgia',
'label' => 'Georgia',
],
],
],
]
);
}
/**
* Transforms a string to camelCase.
*
* @param string $str The string to be transformed.
*
* @return string
*/
function generateblocks_to_camel_case( string $str ): string {
return lcfirst(
str_replace(
'_',
'',
ucwords( $str, '_' )
)
);
}
/**
* Transforms a string to snake_case.
*
* @param string $str The string to be transformed.
*
* @return string
*/
function generateblocks_to_snake_case( string $str ): string {
return strtolower(
preg_replace(
'/(? [],
'version' => '',
],
$base_path = GENERATEBLOCKS_DIR . 'dist/'
) {
if ( ! $filename ) {
return $fallback_assets;
}
$assets_file = $base_path . $filename . '.asset.php';
$compiled_assets = file_exists( $assets_file )
? require $assets_file
: false;
$assets =
isset( $compiled_assets['dependencies'] ) &&
isset( $compiled_assets['version'] )
? $compiled_assets
: $fallback_assets;
return $assets;
}
/**
* Check if a string contains another string.
*
* @param string $haystack The string to search in.
* @param string $needle The string to search for.
*/
function generateblocks_str_contains( $haystack, $needle ) {
if ( function_exists( 'str_contains' ) ) {
return str_contains( $haystack, $needle );
}
return '' !== $needle && false !== strpos( $haystack, $needle );
}
/**
* Check if a string starts with another string.
*
* @since 2.0.0
*
* @param string $string The string to search in.
* @param string $prefix The string to search for.
* @return bool
*/
function generateblocks_str_starts_with( $string, $prefix ) {
if ( function_exists( 'str_starts_with' ) ) {
return str_starts_with( $string, $prefix );
} else {
return substr( $string, 0, strlen( $prefix ) ) === $prefix;
}
}
/**
* Check if we're using the v1 blocks.
*
* @since 2.0.0
* @return bool
*/
function generateblocks_use_v1_blocks() {
$option = get_option( 'gb_use_v1_blocks', false );
return apply_filters(
'generateblocks_use_v1_blocks',
$option
);
}
/**
* Add custom attributes to a block.
*
* @since 2.0.0
* @param array $html_attributes The existing attributes.
* @param array $block_attributes The settings for the block.
*/
function generateblocks_with_html_attributes( $html_attributes, $block_attributes ) {
if ( empty( $block_attributes['htmlAttributes'] ) ) {
return $html_attributes;
}
foreach ( (array) $block_attributes['htmlAttributes'] as $key => $value ) {
if ( ! $key ) {
continue;
}
$escaped_value = generateblocks_get_escaped_html_attribute( $key, $value );
$html_attributes[ $key ] = $escaped_value;
}
return $html_attributes;
}
/**
* Get the classes for a block.
*
* @since 2.0.0
* @param string $block_slug The block slug.
* @param array $block_attributes The block attributes.
* @param bool $with_base_class Whether to include the base class.
*/
function generateblocks_get_block_classes( $block_slug, $block_attributes, $with_base_class = false ) {
$classes = [];
if ( $with_base_class ) {
$classes[] = $block_slug;
}
if ( ! empty( $block_attributes['className'] ) ) {
$classes[] = $block_attributes['className'];
}
if ( ! empty( $block_attributes['globalClasses'] ) ) {
$classes = array_merge(
$classes,
$block_attributes['globalClasses']
);
}
if ( ! empty( $block_attributes['styles'] ) ) {
$classes[] = $block_slug . '-' . $block_attributes['uniqueId'];
}
return $classes;
}
/**
* Get the HTML attributes for a block.
* This function is only used if generateblocks_get_processed_html_attributes() returns nothing.
*
* @since 2.0.0
* @param string $block_slug The block slug.
* @param array $attributes The block attributes.
*/
function generateblocks_get_backup_html_attributes( $block_slug, $attributes ) {
$classes = generateblocks_get_block_classes( $block_slug, $attributes );
return [
'id' => $attributes['anchor'] ?? null,
'class' => implode( ' ', $classes ),
];
}
/**
* Get the HTML attributes from an HTML element.
*
* @since 2.0.0
* @param string $html The HTML.
*/
function generateblocks_get_processed_html_attributes( $html ) {
$html_attributes = [];
if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) {
return $html_attributes;
}
$processor = new WP_HTML_Tag_Processor( $html );
if ( $processor->next_tag() ) {
foreach ( $processor->get_attribute_names_with_prefix( '' ) as $name ) {
$attribute_value = $processor->get_attribute( $name );
$escaped_value = generateblocks_get_escaped_html_attribute( $name, $attribute_value );
$html_attributes[ $name ] = $escaped_value;
}
}
return $html_attributes;
}
/**
* Given an attribute name and value, escape it.
*
* @param string $name The attribute key.
* @param string $value The raw attribute value.
*/
function generateblocks_get_escaped_html_attribute( $name, $value ) {
$is_url_field = generateblocks_is_url_attribute( $name );
if ( $is_url_field && ! empty( $value ) ) {
$value = do_shortcode( $value ); // esc_url() escapes shortcodes, so we need to do this first.
}
return $is_url_field
? esc_url( $value )
: $value; // set_attribute() handles escaping as of WP 6.9.
}
/**
* Escapes all attribute inside of the given block content.
*
* @param string $content The content of the block.
* @param array $args An array of args for the function.
*
* @since 2.0.0
*/
function generateblocks_with_escaped_attributes( $content, $args = [] ) {
$block_html_attributes = $args['block_html_attrs'] ?? [];
$link_html_attributes = $args['link_html_attrs'] ?? [];
if ( empty( $link_html_attributes ) && empty( $block_html_attributes ) ) {
return $content;
}
if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) {
return $content;
}
$max_tags = ! empty( $link_html_attributes ) && ! empty( $block_html_attributes )
? 2
: 1;
$processor = new WP_HTML_Tag_Processor( $content );
$updated = false;
$tags_processed = 0;
while ( $processor->next_tag() && $tags_processed < $max_tags ) {
$tag = $processor->get_tag();
if ( 'STYLE' === $tag ) {
continue;
}
foreach ( $processor->get_attribute_names_with_prefix( '' ) as $name ) {
$attribute_value = $processor->get_attribute( $name );
$escaped_value = generateblocks_get_escaped_html_attribute( $name, $attribute_value );
// WordPress strips out the `download` value by default, even though it's acceptable to give it a value.
// If we have a `download` attribute, let's re-add the value if it exists.
if ( 'download' === $name ) {
$attributes_with_download = $block_html_attributes;
if ( 2 === $max_tags && 0 === $tags_processed ) {
$attributes_with_download = $link_html_attributes;
}
$download_value = $attributes_with_download[ $name ] ?? true;
$escaped_value = generateblocks_get_escaped_html_attribute( $name, $download_value );
}
$processor->set_attribute( $name, $escaped_value );
$updated = true;
}
$tags_processed++;
}
if ( $updated ) {
return $processor->get_updated_html();
}
return $content;
}
/**
* Get a list of our v1 block names.
*
* @since 2.0.0
* @return array The block names.
*/
function generateblocks_get_v1_block_names() {
return [
'generateblocks/button-container',
'generateblocks/button',
'generateblocks/container',
'generateblocks/grid',
'generateblocks/headline',
'generateblocks/image',
'generateblocks/query-loop',
];
}
/**
* Get ACF option field keys.
*
* @since 2.1.2
* @return array The ACF option field keys.
*/
function generateblocks_get_acf_option_field_keys() {
if ( ! function_exists( 'acf_get_option_meta' ) ) {
return [];
}
$acf_options = acf_get_option_meta( 'options' );
if ( ! is_array( $acf_options ) || empty( $acf_options ) ) {
return [];
}
$options = array_filter(
$acf_options,
function( $key ) {
// Only allow string keys that don't start with underscore.
return is_string( $key ) && strpos( $key, '_' ) !== 0;
},
ARRAY_FILTER_USE_KEY
);
return array_keys( $options );
}