[ Avaa Bypassed ]




Upload:

Command:

www-data@18.216.67.104: ~ $
<?php
/**
 * BlockStyles.
 *
 * @since x.x.x
 * @package Magazine Blocks
 */

namespace MagazineBlocks;

defined( 'ABSPATH' ) || exit;

/**
 * Class BlockStyles.
 */
class BlockStyles {

	const TABLET_BREAKPOINT = '62em';
	const MOBILE_BREAKPOINT = '48em';
	const DEVICES           = array(
		'desktop',
		'tablet',
		'mobile',
	);

	/**
	 * Array of blocks data.
	 *
	 * @var array Array of blocks data.
	 */
	private $blocks;

	/**
	 * Current page or template id.
	 *
	 * @var int|string Current page or template id.
	 */
	private $id;

	/**
	 * Force generate.
	 *
	 * @var bool Force generate.
	 */
	private $force_generate;

	/**
	 * Has old button markup.
	 *
	 * @var bool Has old button markup.
	 */
	private $has_old_button_markup;

	/**
	 * Stylesheet filename.
	 *
	 * @var string Stylesheet filename.
	 */
	private $filename;

	/**
	 * Generated styles.
	 *
	 * @var string Generated styles.
	 */
	private $styles;

	/**
	 * Generated css data.
	 *
	 * @var array Generated css.
	 */
	private $css = array();

	/**
	 * Used fonts.
	 *
	 * @var array Used fonts.
	 */
	private $fonts = array();

	/**
	 * Settings.
	 *
	 * @var \MagazineBlocks\Setting
	 */
	private $setting = null;

	/**
	 * Constructor.
	 *
	 * @param array           $blocks Block data.
	 * @param null|int|string $id Current page or template id.
	 * @param bool            $force_generate Force generate styles.
	 */
	public function __construct( array &$blocks, $id = null, bool $force_generate = false ) {
		$this->id             = $id ?? magazine_blocks_get_the_id();
		$this->force_generate = $force_generate;
		$this->blocks         = &$blocks;

		$this->setting = magazine_blocks_get_setting();

		if ( empty( $this->blocks ) || empty( $this->id ) ) {
			return;
		}

		$this->has_old_button_markup = $this->has_old_button_markup();

		$this->maybe_generate();
	}

	/**
	 * Enqueue.
	 *
	 * @param bool|string $version Version.
	 * @return void
	 */
	public function enqueue( $version = false ) {
		if ( empty( $this->styles ) ) {
			return;
		}

		$inline = true;

		if ( ! magazine_blocks_is_preview() ) {
			$inline = ! ( $this->setting->get( 'asset-generation.external-file', false ) && file_exists( MAGAZINE_BLOCKS_UPLOAD_DIR . "/$this->filename" ) );
		}

		if ( ! $inline ) {
			wp_enqueue_style(
				"magazine-blocks-blocks-css-$this->id",
				MAGAZINE_BLOCKS_UPLOAD_DIR_URL . "/$this->filename",
				array( 'magazine-blocks-blocks' ),
				$version // Version is always false, on every build filename is different.
			);
			return;
		}

		wp_add_inline_style( 'magazine-blocks-blocks', $this->styles );
		unset( $this->styles );
	}

	/**
	 * Enqueue Google fonts.
	 *
	 * @param array $additional_fonts Additional fonts.
	 *
	 * @return void
	 */
	public function enqueue_fonts( $additional_fonts = array() ) {
		if ( ! empty( $additional_fonts ) ) {
			foreach ( $additional_fonts as $family => $weight ) {
				if ( isset( $this->fonts[ $family ] ) ) {
					$this->fonts[ $family ] = array_unique( array_merge( $this->fonts[ $family ], $weight ) );
				} else {
					$this->fonts[ $family ] = $weight;
				}
			}
		}

		if ( empty( $this->fonts ) ) {
			return;
		}

		array_walk(
			$this->fonts,
			function( &$value, $key ) {
				$value = trim( $key ) . ':' . trim( rawurlencode( implode( ',', array_unique( $value ) ) ) );
			}
		);


		$google_fonts_url = add_query_arg(
			array(
				'family' => implode( '|', array_values( $this->fonts ) ),
			),
			'https://fonts.googleapis.com/css'
		);

		if ( $this->setting->get( 'performance.local-google-fonts', false ) ) {
			$preload          = $this->setting->get( 'performance.preload-local-fonts', false );
			$google_fonts_url = magazine_blocks_get_webfont_url( $google_fonts_url, 'woff2', $preload );
		}

		wp_enqueue_style(
			'magazine-blocks-google-fonts',
			add_query_arg( 'display', 'swap', $google_fonts_url ),
			array(),
			MAGAZINE_BLOCKS_VERSION
		);
	}

	/**
	 * Get styles.
	 *
	 * @return string
	 */
	public function get_styles() {
		return $this->styles;
	}

	/**
	 * Get fonts.
	 *
	 * @return array
	 */
	public function get_fonts() {
		return $this->fonts;
	}

	/**
	 * Get style filename.
	 *
	 * @return string
	 */
	public function get_filename() {
		return $this->filename;
	}

	/**
	 * Maybe generate.
	 *
	 * @return void
	 */
	private function maybe_generate() {
		$saved = $this->get_saved_styles();

		if ( ! $this->force_generate && ! empty( $saved ) && ! magazine_blocks_is_preview() ) {
			$this->styles   = magazine_blocks_array_get( $saved, 'stylesheet', '' );
			$this->filename = magazine_blocks_array_get( $saved, 'filename', '' );
			$this->fonts    = magazine_blocks_array_get( $saved, 'fonts', array() );
			unset( $this->blocks );
			return;
		}

		try {
			$this->create_style_file();
			$this->generate();
			$this->make_styles();
			$this->update_styles();
			$this->write();
		} catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
			// Do nothing.
		}
	}

	/**
	 * Make styles.
	 *
	 * @return void
	 */
	private function make_styles() {
		if ( empty( $this->css ) ) {
			return;
		}

		$styles            = $this->make_all_device_styles();
		$tablet_breakpoint = $this->setting->get( 'editor.responsive-breakpoints.tablet', self::TABLET_BREAKPOINT ) . 'px';
		$mobile_breakpoint = $this->setting->get( 'editor.responsive-breakpoints.mobile', self::MOBILE_BREAKPOINT ) . 'px';

		$this->styles  = $styles['desktop'];
		$this->styles .= $this->make_media_query_styles( $styles['tablet'], "(max-width: $tablet_breakpoint)" );
		$this->styles .= $this->make_media_query_styles( $styles['mobile'], "(max-width: $mobile_breakpoint)" );
		$this->styles .= $this->make_media_query_styles(
			$styles['tablet_only'],
			"(min-width: $mobile_breakpoint) and (max-width: $tablet_breakpoint)"
		);
		$this->styles .= $this->make_media_query_styles( $styles['desktop_only'], "(min-width: $tablet_breakpoint)" );

		unset( $this->css );
	}

	/**
	 * Make all device styles.
	 *
	 * @return array
	 */
	private function make_all_device_styles() {
		$styles = array(
			'desktop'      => '',
			'tablet'       => '',
			'mobile'       => '',
			'tablet_only'  => '',
			'desktop_only' => '',
		);

		foreach ( $this->css as $device => $css ) {
			$css    = magazine_blocks_array_combine_keys( $css );
			$result = '';

			array_walk(
				$css,
				function ( $declarations, $selector ) use ( &$result ) {
					$styles = '';
					foreach ( $declarations as $property => $value ) {
						$styles .= "$property:$value;";
					}
					$result .= "$selector{{$styles}}";
				}
			);

			$styles[ $device ] .= $result;
		}

		return $styles;
	}

	/**
	 * Make media query styles.
	 *
	 * @param string $styles CSS declarations.
	 * @param string $media_query Media query.
	 *
	 * @return string
	 */
	private function make_media_query_styles( string $styles, string $media_query ) {
		if ( empty( $styles ) ) {
			return '';
		}
		return "@media $media_query{{$styles}}";
	}

	/**
	 * Generate.
	 *
	 * @return void
	 */
	private function generate() {
		foreach ( $this->blocks as $block ) {
			$namespace = $block['blockName'];
			$attrs     = $block['attrs'];

			if ( $this->has_old_button_markup ) {
				$namespace = 'magazine-blocks/button' === $namespace ? 'magazine-blocks/button-inner' : $namespace;
			}

			$name = explode( '/', $namespace )[1];

			$attrs_def = $this->get_attribute_def( $namespace );

			if ( ! $attrs_def || ! isset( $attrs['clientId'] ) ) {
				continue;
			}

			if ( ! $this->has_old_button_markup ) {
				$name = 'button-inner' === $name ? 'button' : ( 'button' === $name ? 'buttons' : $name );
			}

			$wrapper_class = '.mzb-' . $name . '-' . $attrs['clientId'];

			foreach ( $attrs_def as $setting_id => $data ) {
				$styles_def = $data['style'] ?? false;

				if ( empty( $styles_def ) ) {
					continue;
				}

				$value = $this->get_setting_value( $data, $attrs[ $setting_id ] ?? null );

				if ( empty( $value ) ) {
					continue;
				}

				$this->css = magazine_blocks_parse_args(
					$this->css,
					$this->generate_style_by_prop( $value, $styles_def, $attrs, $attrs_def, $wrapper_class )
				);
			}
		}
		unset( $this->blocks );
	}

	/**
	 * Get setting value.
	 *
	 * @param mixed $data Setting definition.
	 * @param mixed $value Setting value.
	 *
	 * @return mixed
	 */
	private function get_setting_value( $data, $value ) {
		$default = magazine_blocks_array_get( $data, 'default' );
		return $value ?? $default;
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function generate_style_by_prop( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		if ( isset( $value['border'] ) ) {
			unset( $value['border'] );
			$callback = array( $this, 'border' );
		} elseif ( isset( $value['background'] ) ) {
			unset( $value['background'] );
			$callback = array( $this, 'background' );
		} elseif ( isset( $value['typography'] ) ) {
			unset( $value['typography'] );
			$this->generate_fonts( $value );
			$callback = array( $this, 'typography' );
		} elseif ( isset( $value['dimension'] ) ) {
			unset( $value['dimension'] );
			$callback = array( $this, 'dimension' );
		} elseif ( isset( $value['boxShadow'] ) ) {
			unset( $value['boxShadow'] );
			$callback = [ $this, 'box_shadow' ];
		} elseif ( isset( $value['topSeparator'] ) || isset( $value['bottomSeparator'] ) ) {
			unset( $value['topSeparator'] );
			unset( $value['bottomSeparator'] );
			$callback = [ $this, 'separator' ];
		} else {
			$callback = array( $this, 'general' );
		}
		return call_user_func_array( $callback, array( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) );
	}

	/**
	 * Generate fonts from blocks.
	 *
	 * @param array $value Setting value.
	 *
	 * @return void
	 */
	private function generate_fonts( array $value ) {
		if ( ! isset( $value['family'] ) || 'default' === strtolower( $value['family'] ) ) {
			return;
		}

		$weight = (string) ( $value['weight'] ?? '400' );
		$family = $value['family'];

		if ( ! isset( $this->fonts[ $family ] ) ) {
			$this->fonts[ $family ] = array( $weight );
		} else { // phpcs:ignore Universal.ControlStructures.DisallowLonelyIf.Found
			if ( ! in_array( $weight, $this->fonts[ $family ], true ) ) {
				$this->fonts[ $family ][] = $weight;
			}
		}
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function border( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array();

		if ( empty( $value ) ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );
			$style    = magazine_blocks_array_get( $value, 'type', 'none' );

			if ( 'none' !== $style ) {
				$css['desktop'][ $selector ]['border-style'] = $style;

				if ( isset( $value['color'] ) ) {
					$css['desktop'][ $selector ]['border-color'] = $value['color'];
				}

				$this->process_border_size_styles( $value, $selector, $css );
			}
			$this->process_border_radius_styles( $value, $selector, $css );
		}

		return $css;
	}

	/**
	 * Process border size styles.
	 *
	 * @param array  $value Setting value.
	 * @param string $selector CSS selector.
	 * @param array  $css CSS.
	 *
	 * @return void
	 */
	private function process_border_size_styles( $value, $selector, &$css ) {
		if ( ! isset( $value['size'] ) ) {
			return;
		}
		foreach ( self::DEVICES as $device ) {
			$device_val = magazine_blocks_array_get( $value, "size.$device", array() );
			$val        = $this->sides_style( $device_val );
			if ( false !== $val ) {
				$css[ $device ][ $selector ]['border-width'] = $val;
			}
		}
	}

	/**
	 * Process border radius styles.
	 *
	 * @param array  $value Setting value.
	 * @param string $selector CSS selector.
	 * @param array  $css CSS.
	 *
	 * @return void
	 */
	private function process_border_radius_styles( $value, $selector, &$css ) {
		if ( ! isset( $value['radius'] ) ) {
			return;
		}
		foreach ( self::DEVICES as $device ) {
			$device_val = magazine_blocks_array_get( $value, "radius.$device", array() );
			$val        = $this->sides_style( $device_val );
			if ( false !== $val ) {
				$css[ $device ][ $selector ]['border-radius'] = $val;
			}
		}
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function dimension( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array(
			'desktop' => array(),
			'tablet'  => array(),
			'mobile'  => array(),
		);

		if ( empty( $value ) ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );

			if ( magazine_blocks_array_has_any( $value, self::DEVICES ) ) {
				foreach ( self::DEVICES as $device ) {
					$val = $this->sides_style( $value[ $device ] ?? array() );
					if ( false === $val ) {
						continue;
					}
					$css[ $device ] = magazine_blocks_parse_args(
						$css[ $device ],
						$this->parse_css_string(
							str_replace( '{{VALUE}}', $val, $selector )
						)
					);
				}
			} else {
				$val = $this->sides_style( $value );
				if ( false !== $val ) {
					$css['desktop'] = magazine_blocks_parse_args(
						$css['desktop'],
						$this->parse_css_string(
							str_replace( '{{VALUE}}', $val, $selector )
						)
					);
				}
			}
		}

		return $css;
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function background( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array();

		if ( empty( $value ) ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}
			$selector = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );

			if ( isset( $value['color'] ) ) {
				$css['desktop'][ $selector ]['background-color'] = $value['color'];
			}

			$url = magazine_blocks_array_get( $value, 'image.image.url' );
			$url = $url ?? magazine_blocks_array_get( $value, 'image.image.local' );
			$url = $url ?? magazine_blocks_array_get( $value, 'image.image.external' );

			if ( empty( $url ) ) {
				continue;
			}

			$css['desktop'][ $selector ]['background-image'] = "url($url)";

			$attachment = magazine_blocks_array_get( $value, 'image.attachment', 'default' );

			if ( 'default' !== $attachment ) {
				$css['desktop'][ $selector ]['background-attachment'] = $attachment;
			}

			$this->process_responsive_background_styles( $value, $selector, $css );
		}

		return $css;
	}

	/**
	 * Process responsive background styles.
	 *
	 * @param array  $value Setting value.
	 * @param string $selector CSS selector.
	 * @param array  $css CSS.
	 *
	 * @return void
	 */
	private function process_responsive_background_styles( $value, $selector, &$css ) {
		foreach ( self::DEVICES as $device ) {
			$position = magazine_blocks_array_get( $value, "image.position.$device", 'default' );
			$repeat   = magazine_blocks_array_get( $value, "image.repeat.$device", 'default' );
			$size     = magazine_blocks_array_get( $value, "image.size.$device", 'default' );
			if ( 'default' !== $position ) {
				$css[ $device ][ $selector ]['background-position'] = $position;
			}
			if ( 'default' !== $repeat ) {
				$css[ $device ][ $selector ]['background-repeat'] = $repeat;
			}
			if ( 'default' !== $size || 'custom' !== $size ) {
				$css[ $device ][ $selector ]['background-size'] = $size;
			}
			if ( 'custom' === $size ) {
				$key         = 'customSize' . ucfirst( $device );
				$custom_size = magazine_blocks_array_get( $value, "image.$key.value" );
				$custom_unit = magazine_blocks_array_get( $value, "image.$key.unit", 'px' );
				if ( $custom_size ) {
					$css[ $device ][ $selector ]['background-size'] = "$custom_size$custom_unit auto";
				}
			}
		}
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function box_shadow( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array();

		if ( ! isset( $value['enable'] ) || ! $value['enable'] ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector     = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );
			$position     = magazine_blocks_array_get( $value, 'position', 'outline' );
			$horizontal_x = magazine_blocks_array_get( $value, 'horizontalX', '0' );
			$vertical_y   = magazine_blocks_array_get( $value, 'verticalY', '0' );
			$blur         = magazine_blocks_array_get( $value, 'blur', '0' );
			$spread       = magazine_blocks_array_get( $value, 'spread', '0' );
			$color        = magazine_blocks_array_get( $value, 'color', 'rgba(0,0,0, 0.5)' );

			$css['desktop'][ $selector ]['box-shadow'] = sprintf(
				'%s%spx %spx %spx %spx %s',
				'inset' === $position ? 'inset ' : '',
				$horizontal_x,
				$vertical_y,
				$blur,
				$spread,
				$color
			);
		}

		return $css;
	}

	/**
	 * Generate separator css.
	 *
	 * @param array $value Separator value.
	 * @param array $styles_def Styles definition.
	 * @param array $attrs Saved attributes.
	 * @param array $attrs_def Attributes definition.
	 * @param string $wrapper_class Wrapper class.
	 * @return void
	 */
	private function separator( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = [];

		if ( ! isset( $value['enable'] ) || ! $value['enable'] ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector     = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );
			$fill         = magazine_blocks_array_get( $value, 'color', '#fff' );
			$height       = magazine_blocks_array_get( $value, 'height', 100 );
			$width        = magazine_blocks_array_get( $value, 'width', 1 );
			$shadow_color = magazine_blocks_array_get( $value, 'shadow_color', '#fff' );
			$horizontal_x = magazine_blocks_array_get( $value, 'horizontalX', 0 );
			$vertical_y   = magazine_blocks_array_get( $value, 'verticalY', 0 );
			$blur         = magazine_blocks_array_get( $value, 'blur', 0 );

			$css['desktop'][ $selector ]['fill']      = $fill;
			$css['desktop'][ $selector ]['height']    = $height . 'px';
			$css['desktop'][ $selector ]['transform'] = 'scaleX(' . $width . ')';
			$css['desktop'][ $selector ]['filter']    = 'drop-shadow(' . $horizontal_x . 'px ' . $vertical_y . 'px ' . $blur . 'px ' . $shadow_color . ')';
		}

		return $css;
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function typography( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array();
		if ( empty( $value ) ) {
			return $css;
		}
		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}

			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector   = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );
			$family     = magazine_blocks_array_get( $value, 'family', 'Default' );
			$weight     = magazine_blocks_array_get( $value, 'weight' );
			$transform  = magazine_blocks_array_get( $value, 'transform', 'default' );
			$decoration = magazine_blocks_array_get( $value, 'decoration', 'default' );

			if ( 'default' !== strtolower( $family ) ) {
				$css['desktop'][ $selector ]['font-family'] = $family;
			}
			if ( $weight ) {
				$css['desktop'][ $selector ]['font-weight'] = $weight;
			}
			if ( 'default' !== strtolower( $transform ) ) {
				$css['desktop'][ $selector ]['text-transform'] = $transform;
			}
			if ( 'default' !== strtolower( $decoration ) ) {
				$css['desktop'][ $selector ]['text-decoration'] = $decoration;
			}

			$this->process_responsive_typography_styles( $value, $selector, $css );
		}
		return $css;
	}

	/**
	 * Process responsive typography styles.
	 *
	 * @param array  $value Setting value.
	 * @param string $selector CSS selector.
	 * @param array  $css CSS.
	 *
	 * @return void
	 */
	private function process_responsive_typography_styles( $value, $selector, &$css ) {
		foreach ( self::DEVICES as $device ) {
			$size                = magazine_blocks_array_get( $value, "size.$device.value", false );
			$size_unit           = magazine_blocks_array_get( $value, "size.$device.unit", 'px' );
			$line_height         = magazine_blocks_array_get( $value, "lineHeight.$device.value", false );
			$line_height_unit    = magazine_blocks_array_get( $value, "lineHeight.$device.unit", 'px' );
			$letter_spacing      = magazine_blocks_array_get( $value, "letterSpacing.$device.value", false );
			$letter_spacing_unit = magazine_blocks_array_get( $value, "letterSpacing.$device.unit", 'px' );
			if ( $size ) {
				$css[ $device ][ $selector ]['font-size'] = $size . $size_unit;
			}
			if ( $line_height ) {
				$css[ $device ][ $selector ]['line-height'] = $line_height . $line_height_unit;
			}
			if ( $letter_spacing ) {
				$css[ $device ][ $selector ]['letter-spacing'] = $letter_spacing . $letter_spacing_unit;
			}
		}
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function general( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = array(
			'desktop'      => array(),
			'tablet'       => array(),
			'mobile'       => array(),
			'tablet_only'  => array(),
			'desktop_only' => array(),
		);

		if ( empty( $value ) ) {
			return $css;
		}
		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? array(), $attrs, $attrs_def ) ) {
				continue;
			}

			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );

			if ( false === strpos( $selector, '{{VALUE}}' ) ) {
				$this->process_non_value_selector( $selector, $css );
				continue;
			}

			if ( ! $value ) {
				continue;
			}

			$this->process_value_selector( $value, $selector, $css );
		}

		return $css;
	}

	/**
	 * Generate style by prop.
	 *
	 * @param mixed  $value Setting value.
	 * @param array  $styles_def Styles definition.
	 * @param array  $attrs Block attributes.
	 * @param array  $attrs_def Block attributes def.
	 * @param string $wrapper_class Wrapper id.
	 *
	 * @return array
	 */
	private function list_gap( $value, $styles_def, $attrs, $attrs_def, $wrapper_class ) {
		$css = [];

		if ( ! isset( $value['enable'] ) || ! $value['enable'] ) {
			return $css;
		}

		foreach ( $styles_def as $style_def ) {
			if ( ! $this->check_condition( $style_def['condition'] ?? [], $attrs, $attrs_def ) ) {
				continue;
			}
			if ( ! isset( $style_def['selector'] ) ) {
				continue;
			}

			$selector = str_replace( '{{WRAPPER}}', $wrapper_class, $style_def['selector'] );

			// Retrieve the slider value for padding (divided by 2)
			$slider_value = magazine_blocks_array_get( $value, 'sliderValue', '0' );

			// Calculate the padding value based on the slider value
			$padding_value = $slider_value / 2;

			// Generate CSS rules for padding for the selector
			$css['desktop'][ $selector ]['padding-top'] = $padding_value . 'px';
			$css['desktop'][ $selector ]['padding-bottom'] = $padding_value . 'px';
		}

		return $css;
	}



	/**
	 * This function processes CSS selectors and assigns them to specific CSS arrays based on their media
	 * query properties.
	 *
	 * @param string $selector The CSS selector to be processed.
	 * @param array  $css  is an associative array that contains different CSS styles for different screen
	 * sizes. The keys of the array are 'mobile', 'tablet', 'desktop', 'tablet_only', and 'desktop_only'.
	 * The values of the array are CSS declarations in string format.
	 */
	private function process_non_value_selector( $selector, &$css ) {
		if ( false !== strpos( $selector, '@media' ) ) {
			$this->process_media_query_styles( $selector, $css );
		} else {
			$css['desktop'] = magazine_blocks_parse_args( $css['mobile'], $this->parse_css_string( $selector ) );
		}
	}

	/**
	 * Process media query styles.
	 *
	 * @param mixed $selector CSS selector.
	 * @param mixed $css Process css.
	 *
	 * @return void
	 */
	private function process_media_query_styles( $selector, &$css ) {
		preg_match( '/@media\s*\((.*?)\)\s*{(.*?)}/', $selector, $matches );

		$desktop_only = 'min-width:62em';
		$tablet_only  = 'min-width:48em) and (max-width:62em';
		$mobile       = 'max-width:48em';
		$tablet       = 'max-width:62em';

		if ( empty( $matches[1] ) || empty( $matches[2] ) ) {
			return;
		}

		$media_query  = $matches[1];
		$declarations = $matches[2];
		$declarations = substr( $declarations, -1 ) !== '}' ? $declarations . '}' : $declarations;
		$declarations = $this->parse_css_string( $declarations );

		if ( strpos( $media_query, $tablet_only ) !== false ) {
			$css['tablet_only'] = magazine_blocks_parse_args( $css['tablet_only'], $declarations );
			return;
		}
		if ( strpos( $media_query, $desktop_only ) !== false ) {
			$css['desktop_only'] = magazine_blocks_parse_args( $css['desktop_only'], $declarations );
			return;
		}
		if ( strpos( $media_query, $mobile ) !== false ) {
			$css['mobile'] = magazine_blocks_parse_args( $css['mobile'], $declarations );
			return;
		}
		if ( strpos( $media_query, $tablet ) !== false ) {
			$css['tablet'] = magazine_blocks_parse_args( $css['tablet'], $declarations );
		}
	}


	/**
	 * The method processes a value selector for CSS styling, taking into account different devices and
	 * units.
	 *
	 * @param mixed  $value The value to be processed. It can be a string or an array containing values for different devices.
	 * @param string $selector The CSS selector to apply the value to.
	 * @param array  $css is a reference to an array that contains CSS styles for different devices (desktop,
	 * tablet, mobile). The function updates this array with new styles based on the value and selector
	 * parameters.
	 */
	private function process_value_selector( $value, $selector, &$css ) {
		if ( is_array( $value ) ) {
			if ( count( array_intersect( array_keys( $value ), array( 'desktop', 'tablet', 'mobile' ) ) ) > 0 ) {
				foreach ( self::DEVICES as $device ) {
					if ( ! isset( $value[ $device ] ) ) {
						continue;
					}
					if ( is_array( $value[ $device ] ) ) {
						if ( isset( $value[ $device ]['value'] ) ) {
							$unit           = $value[ $device ]['unit'] ?? 'px';
							$temp           = str_replace( '{{VALUE}}', "{$value[ $device ]['value']}$unit", $selector );
							$css[ $device ] = magazine_blocks_parse_args( $css[ $device ], $this->parse_css_string( $temp ) );
						}
					} else {
						$css[ $device ] = magazine_blocks_parse_args(
							$css[ $device ],
							$this->parse_css_string( str_replace( '{{VALUE}}', $value[ $device ], $selector ) )
						);
					}
				}
			} elseif ( isset( $value['value'] ) ) {
				$unit           = $value['unit'] ?? 'px';
				$css['desktop'] = magazine_blocks_parse_args(
					$css['desktop'],
					$this->parse_css_string( str_replace( '{{VALUE}}', "{$value['value']}$unit", $selector ) )
				);
			}
		} else {
			$css['desktop'] = magazine_blocks_parse_args(
				$css['desktop'],
				$this->parse_css_string( str_replace( '{{VALUE}}', $value, $selector ) )
			);
		}
	}

	/**
	 * Parses a CSS string and returns an array of selectors and their corresponding
	 * properties.
	 *
	 * @param string $css_string A string containing CSS rules and declarations.
	 *
	 * @return array An array containing parsed CSS rules, where each selector is a key and its
	 * corresponding properties are stored as an array.
	 */
	private function parse_css_string( string $css_string ): array {
		$css   = array();
		$rules = explode( '}', $css_string );
		foreach ( $rules as $rule ) {
			$parts = explode( '{', $rule, 2 );
			if ( ! isset( $parts[1] ) ) {
				continue;
			}
			$selector   = trim( $parts[0] );
			$properties = array();
			$pairs      = explode( ';', trim( $parts[1] ) );
			foreach ( $pairs as $pair ) {
				$pos = strpos( $pair, ':' );
				if ( false === $pos ) {
					continue;
				}
				$prop                = trim( substr( $pair, 0, $pos ) );
				$val                 = trim( substr( $pair, $pos + 1 ) );
				$properties[ $prop ] = $val;
			}
			$css[ $selector ] = $properties;
		}
		return $css;
	}

	/**
	 * Side styles.
	 *
	 * @param mixed $value Setting value.
	 *
	 * @return string
	 */
	private function sides_style( $value ) {
		if ( magazine_blocks_array_has_any( $value, array( 'top', 'right', 'bottom', 'left' ) ) ) {
			$unit                = magazine_blocks_array_get( $value, 'unit', 'px' );
			$top                 = magazine_blocks_array_get( $value, 'top', 0 );
			$right               = magazine_blocks_array_get( $value, 'right', 0 );
			$bottom              = magazine_blocks_array_get( $value, 'bottom', 0 );
			$left                = magazine_blocks_array_get( $value, 'left', 0 );
			$is_equal            = $top === $right && $right === $bottom && $bottom === $left;
			$is_top_bottom_equal = $top === $bottom;
			$is_left_right_equal = $left === $right;

			if ( $is_equal ) {
				return "$top$unit";
			}

			if ( $is_top_bottom_equal && $is_left_right_equal ) {
				return "$top$unit $left$unit";
			}

			return "$top$unit $right$unit $bottom$unit $left$unit";
		}

		return false;
	}

	/**
	 * Get attribute definition.
	 *
	 * @param mixed $block_namespace Block namespace.
	 * @return array|bool
	 */
	private function get_attribute_def( $block_namespace ) {
		return \WP_Block_Type_Registry::get_instance()
			->get_all_registered()[ $block_namespace ]->attributes ?? false;
	}

	/**
	 * Get saved styles.
	 *
	 * @return array|false
	 */
	private function get_saved_styles() {
		return is_int( $this->id ) ?
			get_post_meta( $this->id, '_magazine_blocks_blocks_css', true ) :
			get_option( '_magazine_blocks_blocks_css', array() )[ $this->id ] ?? [];
	}

	/**
	 * Updates the styles data.
	 */
	private function update_styles() {
		$styles_data = array(
			'filename'   => $this->filename,
			'fonts'      => $this->fonts,
			'stylesheet' => $this->styles,
		);

		if ( is_int( $this->id ) ) {
			update_post_meta( $this->id, '_magazine_blocks_blocks_css', $styles_data );
			return;
		}

		$saved              = get_option( '_magazine_blocks_blocks_css', array() );
		$saved[ $this->id ] = $styles_data;

		update_option( '_magazine_blocks_blocks_css', $saved );
	}

	/**
	 * Check if has old button markup.
	 *
	 * @return bool
	 */
	private function has_old_button_markup() {
		foreach ( $this->blocks as $block ) {
			if ( 'magazine-blocks/button' === $block['blockName'] && empty( $block['innerBlocks'] ) ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * This function creates a CSS file with a unique filename and deletes any existing CSS files with a
	 * similar name.
	 *
	 * @return false|true false or the result of the `touch` method of the `` object.
	 */
	private function create_style_file() {
		$filesystem = magazine_blocks_get_filesystem();

		if ( ! $filesystem ) {
			return false;
		}

		if (
			! $filesystem->is_dir( MAGAZINE_BLOCKS_UPLOAD_DIR ) &&
			! $filesystem->mkdir( MAGAZINE_BLOCKS_UPLOAD_DIR, FS_CHMOD_DIR )
		) {
			return false;
		}

		$files = $filesystem->dirlist( MAGAZINE_BLOCKS_UPLOAD_DIR );

		if ( $files ) {
			foreach ( $files as $file ) {
				if ( false !== strpos( $file['name'], "mzb-style-$this->id-" ) ) {
					$filesystem->delete( MAGAZINE_BLOCKS_UPLOAD_DIR . '/' . $file['name'] );
				}
			}
		}

		$this->filename = "mzb-style-$this->id-" . time() . '.css';

		return $filesystem->touch( MAGAZINE_BLOCKS_UPLOAD_DIR . '/' . $this->filename );
	}


	/**
	 * This function writes the contents of a file to a specified directory using the Magazine Blocks filesystem.
	 */
	private function write() {
		$filesystem = magazine_blocks_get_filesystem();
		if ( $filesystem ) {
			$filesystem->put_contents( MAGAZINE_BLOCKS_UPLOAD_DIR . '/' . $this->filename, $this->styles );
		}
	}

	/**
	 * Check condition.
	 *
	 * @param array $conditions Conditions to check.
	 * @param array $attrs Block attributes.
	 * @param array $attrs_def Block attributes definition.
	 *
	 * @return boolean
	 */
	private function check_condition( $conditions, $attrs, $attrs_def ) {
		$result = true;

		if ( empty( $conditions ) ) {
			return $result;
		}

		foreach ( $conditions as $condition ) {
			$previous = $result;
			$key      = $condition['key'];
			$value    = magazine_blocks_array_get( $attrs, $key );
			$value    = $value ?? magazine_blocks_array_get( $attrs_def, "$key.default", false );

			if ( ! $value ) {
				continue;
			}

			$relation              = magazine_blocks_array_get( $condition, 'relation', '' );
			$condition_value       = magazine_blocks_array_get( $condition, 'value', '' );
			$is_equal_relation     = '==' === $relation || '===' === $relation;
			$is_non_equal_relation = '!=' === $relation || '!==' === $relation;

			if ( $is_equal_relation ) {
				if ( is_scalar( $condition_value ) ) {
					$result = $value === $condition_value;
				} else {
					$result = in_array( $value, $condition_value, true );
				}
			} elseif ( $is_non_equal_relation ) {
				if ( is_scalar( $condition_value ) ) {
					$result = $value !== $condition_value;
				} else {
					$result = ! in_array( $value, $condition_value, true );
				}
			}

			if ( ! $previous ) {
				$result = false;
			}
		}

		return $result;
	}
}

Filemanager

Name Type Size Permission Actions
BlockTypes Folder 0777
Helpers Folder 0777
RestApi Folder 0777
traits Folder 0777
Activation.php File 477 B 0644
Admin.php File 5.58 KB 0644
Ajax.php File 2.27 KB 0644
BlockStyles.php File 34.87 KB 0644
Blocks.php File 13.08 KB 0644
Deactivation.php File 564 B 0644
Functions.php File 2.29 KB 0644
Helper.php File 3.32 KB 0644
Icon.php File 3.86 KB 0644
MagazineBlocks.php File 2.83 KB 0644
MaintenanceMode.php File 3.1 KB 0644
Review.php File 6.64 KB 0644
ScriptStyle.php File 10.25 KB 0644
Setting.php File 5.57 KB 0644
Update.php File 1.93 KB 0644
Utils.php File 5.77 KB 0644
WebFontLoader.php File 17.23 KB 0644