: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
namespace WPForms\Frontend;
'field-border-radius' => '3px',
'field-border-style' => 'solid',
'field-border-size' => '1px',
'field-background-color' => self::WHITE,
'field-border-color' => 'rgba( 0, 0, 0, 0.25 )',
'field-text-color' => 'rgba( 0, 0, 0, 0.7 )',
'field-menu-color' => self::WHITE,
'label-color' => 'rgba( 0, 0, 0, 0.85 )',
'label-sublabel-color' => 'rgba( 0, 0, 0, 0.55 )',
'label-error-color' => '#d63637',
'button-border-radius' => '3px',
'button-border-style' => 'none',
'button-border-size' => '1px',
'button-background-color' => '#066aab',
'button-border-color' => '#066aab',
'button-text-color' => self::WHITE,
'page-break-color' => '#066aab',
'background-image' => 'none',
'background-position' => 'center center',
'background-repeat' => 'no-repeat',
'background-size' => 'cover',
'background-width' => '100px',
'background-height' => '100px',
'background-color' => 'rgba( 0, 0, 0, 0 )',
'background-url' => 'url()',
'container-padding' => '0px',
'container-border-style' => 'none',
'container-border-width' => '1px',
'container-border-color' => '#000000',
'container-border-radius' => '3px',
* Container shadow vars and values.
const CONTAINER_SHADOW_SIZE = [
'box-shadow' => '0px 3px 5px 0px rgba(0, 0, 0, 0.1)',
'box-shadow' => '0px 10px 20px 0px rgba(0, 0, 0, 0.1)',
'box-shadow' => '0px 30px 50px -10px rgba(0, 0, 0, 0.15)',
* Field Size vars and values.
'input-height' => '31px',
'input-spacing' => '10px',
'checkbox-size' => '14px',
'sublabel-spacing' => '5px',
'input-height' => '43px',
'input-spacing' => '15px',
'checkbox-size' => '16px',
'sublabel-spacing' => '5px',
'input-height' => '50px',
'input-spacing' => '20px',
'checkbox-size' => '18px',
'sublabel-spacing' => '10px',
* Label Size vars and values.
'sublabel-font-size' => '13px',
'sublabel-line-height' => '16px',
'sublabel-font-size' => '14px',
'sublabel-line-height' => '17px',
'sublabel-font-size' => '16px',
'sublabel-line-height' => '19px',
* Button Size vars and values.
const SPARE_VARS = [ 'field-border-color' ];
* Flag to check if root CSS vars were output.
private $is_root_vars_displayed;
private function hooks() {
add_action( 'wp_head', [ $this, 'output_root' ], PHP_INT_MAX );
private function init_vars() {
$vars[':root'] = array_merge(
$this->get_complex_vars( 'field-size', self::FIELD_SIZE['medium'] ),
$this->get_complex_vars( 'label-size', self::LABEL_SIZE['medium'] ),
$this->get_complex_vars( 'button-size', self::BUTTON_SIZE['medium'] ),
$this->get_complex_vars( 'container-shadow-size', self::CONTAINER_SHADOW_SIZE['none'] )
* Allows developers to modify default CSS variables which output on the frontend.
* @param array $vars CSS variables two-dimensional array.
* First level keys is the CSS selector.
* Second level keys is the variable name without the `--wpforms-` prefix.
$this->css_vars = apply_filters( 'wpforms_frontend_css_vars_init_vars', $vars );
* Get complex CSS variables data.
* @param string $prefix CSS variable prefix.
* @param array $values Values.
public function get_complex_vars( $prefix, $values ): array {
foreach ( $values as $key => $value ) {
$vars[ "{$prefix}-{$key}" ] = $value;
* Get CSS variables data by selector.
* @param string $selector Selector.
public function get_vars( $selector ): array {
if ( empty( $selector ) ) {
if ( empty( $this->css_vars[ $selector ] ) ) {
return $this->css_vars[ $selector ];
* Output root CSS variables.
* @since 1.8.1.2 Added $force argument.
* @param bool $force Force output root variables.
public function output_root( $force = false ) {
if ( ! empty( $this->is_root_vars_displayed ) && empty( $force ) ) {
$this->output_selector_vars( ':root', $this->css_vars[':root'] );
$this->is_root_vars_displayed = true;
* Output selector's CSS variables.
* @param string $selector Selector.
* @param array $vars Variables data.
* @param string $style_id Style tag ID attribute. Optional. Default is empty string.
* @param string|int $form_id Form ID. Optional. Default is empty string.
public function output_selector_vars( $selector, $vars, $style_id = '', $form_id = '' ) {
if ( empty( $this->render_engine ) ) {
$this->render_engine = wpforms_get_render_engine();
if ( $this->render_engine === 'classic' ) {
$style_id = empty( $style_id ) ? 'wpforms-css-vars-' . $selector : $style_id;
sanitize_key( $style_id ),
$selector, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
esc_html( $this->get_vars_css( $vars, $form_id ) )
* @param array $vars Variables data.
* @param string|int $form_id Form ID. Optional. Default is empty string.
private function get_pre_print_vars( array $vars, $form_id = '' ): array {
// Normalize the `background-url` variable.
if ( isset( $vars['background-url'] ) ) {
$vars['background-url'] = $vars['background-url'] === 'url()' ? 'none' : $vars['background-url'];
* Filter CSS variables right before printing the CSS.
* @param array $vars CSS variables.
* @param int $form_id Form ID. Optional. Default is empty string.
return (array) apply_filters( 'wpforms_frontend_css_vars_pre_print_filter', $vars, $form_id );
* Generate CSS code from given vars data.
* @param array $vars Variables data.
* @param string|int $form_id Form ID. Optional. Default is empty string.
private function get_vars_css( $vars, $form_id = '' ): string {
$vars = $this->get_pre_print_vars( (array) $vars, $form_id );
foreach ( $vars as $name => $value ) {
$result .= "--wpforms-{$name}: {$value};\n";
if ( in_array( $name, self::SPARE_VARS, true ) ) {
$result .= "--wpforms-{$name}-spare: {$value};\n";
* Get customized CSS vars.
* @param array $attr Attributes passed by integration.
public function get_customized_css_vars( $attr ): array { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded
$root_css_vars = $this->get_vars( ':root' );
foreach ( $attr as $key => $value ) {
$var_name = strtolower( preg_replace( '/[A-Z]/', '-$0', $key ) );
// Skip attribute that is not the CSS var or has the default value.
if ( empty( $root_css_vars[ $var_name ] ) || $root_css_vars[ $var_name ] === $value ) {
$css_vars[ $var_name ] = $value;
// Reset border size in case of border style is `none`.
if ( isset( $css_vars['field-border-style'] ) && $css_vars['field-border-style'] === 'none' ) {
$css_vars['field-border-size'] = '0px';
if ( isset( $css_vars['button-border-style'] ) && $css_vars['button-border-style'] === 'none' ) {
$css_vars['button-border-size'] = '0px';
// Set the button alternative background color and use border color for accent in case of transparent color.
$button_bg_color = $css_vars['button-background-color'] ?? $root_css_vars['button-background-color'];
if ( $this->is_transparent_color( $button_bg_color ) ) {
$css_vars['button-background-color-alt'] = $button_bg_color;
$border_color = $css_vars['button-border-color'] ?? $root_css_vars['button-border-color'];
$css_vars['button-background-color'] = $this->is_transparent_color( $border_color ) ? $root_css_vars['button-background-color'] : $border_color;
$button_bg_color = $css_vars['button-background-color'];
$button_bg_color = strtolower( $button_bg_color );
// Set the button alternative text color in case if the background and text color are identical.
$button_text_color = strtolower( $css_vars['button-text-color'] ?? $root_css_vars['button-text-color'] );
if ( $button_bg_color === $button_text_color || $this->is_transparent_color( $button_text_color ) ) {
$css_vars['button-text-color-alt'] = $this->get_contrast_color( $button_bg_color );
$size_css_vars = $this->get_size_css_vars( $attr );
return array_merge( $css_vars, $size_css_vars );
* Checks if the provided color has transparency.
* @param string $color The color to check.
private function is_transparent_color( $color ): bool {
$rgba = $this->get_color_as_rgb_array( $color );
$opacity_threshold = 0.33;
$opacity = $rgba[3] ?? 1;
return $opacity < $opacity_threshold;