OwlCyberSecurity - MANAGER
Edit File: class-theme-controller.php
<?php /** * This file is part of the MailPoet Email Editor package. * * @package MailPoet\EmailEditor */ declare(strict_types = 1); namespace MailPoet\EmailEditor\Engine; use WP_Block_Template; use WP_Post; use WP_Theme_JSON; use WP_Theme_JSON_Resolver; /** * E-mail editor works with own theme.json which defines settings for the editor and styles for the e-mail. * This class is responsible for accessing data defined by the theme.json. */ class Theme_Controller { /** * Core theme loaded from the WordPress core. * * @var WP_Theme_JSON */ private WP_Theme_JSON $core_theme; /** * Base theme loaded from a file in the package directory. * * @var WP_Theme_JSON */ private WP_Theme_JSON $base_theme; /** * User theme contains user custom styles and settings * * @var User_Theme */ private User_Theme $user_theme; /** * Theme_Controller constructor. */ public function __construct() { $this->core_theme = WP_Theme_JSON_Resolver::get_core_data(); $this->base_theme = new WP_Theme_JSON( (array) json_decode( (string) file_get_contents( __DIR__ . '/theme.json' ), true ), 'default' ); $this->user_theme = new User_Theme(); } /** * Gets combined theme data from the core and base theme, merged with the user . * * @return WP_Theme_JSON */ public function get_theme(): WP_Theme_JSON { $theme = $this->get_base_theme(); $theme->merge( $this->user_theme->get_theme() ); return $theme; } /** * Gets combined theme data from the core and base theme. * * @return WP_Theme_JSON */ public function get_base_theme(): WP_Theme_JSON { $theme = new WP_Theme_JSON(); $theme->merge( $this->core_theme ); $theme->merge( $this->base_theme ); return apply_filters( 'mailpoet_email_editor_theme_json', $theme ); } /** * Replace preset variables with their values. * * @param array $values Styles array. * @param array $presets Presets array. * @return array */ private function recursive_replace_presets( $values, $presets ) { foreach ( $values as $key => $value ) { if ( is_array( $value ) ) { $values[ $key ] = $this->recursive_replace_presets( $value, $presets ); } elseif ( is_string( $value ) ) { $values[ $key ] = preg_replace( array_keys( $presets ), array_values( $presets ), $value ); } else { $values[ $key ] = $value; } } return $values; } /** * Replace preset variables with their values. * * @param array $styles Styles array. * @return array */ private function recursive_extract_preset_variables( $styles ) { foreach ( $styles as $key => $style_value ) { if ( is_array( $style_value ) ) { $styles[ $key ] = $this->recursive_extract_preset_variables( $style_value ); } elseif ( strpos( $style_value, 'var:preset|' ) === 0 ) { /** @var string $style_value */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort $styles[ $key ] = 'var(--wp--' . str_replace( '|', '--', str_replace( 'var:', '', $style_value ) ) . ')'; } else { $styles[ $key ] = $style_value; } } return $styles; } /** * Get styles for the e-mail. * * @return array{ * spacing: array{ * blockGap: string, * padding: array{bottom: string, left: string, right: string, top: string} * }, * color: array{ * background: string * }, * typography: array{ * fontFamily: string * } * } */ public function get_styles(): array { $theme_styles = $this->get_theme()->get_data()['styles']; // Extract preset variables. $theme_styles = $this->recursive_extract_preset_variables( $theme_styles ); // Replace preset values. $variables = $this->get_variables_values_map(); $presets = array(); foreach ( $variables as $name => $value ) { $pattern = '/var\(' . preg_quote( $name, '/' ) . '\)/i'; $presets[ $pattern ] = $value; } /* @phpstan-ignore-next-line Return type defined above. */ return $this->recursive_replace_presets( $theme_styles, $presets ); } /** * Get settings from the theme. * * @return array */ public function get_settings(): array { $email_editor_theme_settings = $this->get_theme()->get_settings(); $site_theme_settings = WP_Theme_JSON_Resolver::get_theme_data()->get_settings(); $email_editor_theme_settings['color']['palette']['theme'] = array(); if ( isset( $site_theme_settings['color']['palette']['theme'] ) ) { $email_editor_theme_settings['color']['palette']['theme'] = $site_theme_settings['color']['palette']['theme']; } return $email_editor_theme_settings; } /** * Get layout settings from the theme. * * @return array{contentSize: string, wideSize: string, allowEditing?: bool, allowCustomContentAndWideSize?: bool} */ public function get_layout_settings(): array { return $this->get_theme()->get_settings()['layout']; } /** * Get stylesheet from context. * * @param string $context Context. * @param array $options Options. * @return string */ public function get_stylesheet_from_context( $context, $options = array() ): string { return function_exists( 'gutenberg_style_engine_get_stylesheet_from_context' ) ? gutenberg_style_engine_get_stylesheet_from_context( $context, $options ) : wp_style_engine_get_stylesheet_from_context( $context, $options ); } /** * Get stylesheet for rendering. * * @param WP_Post|null $post Post object. * @param WP_Block_Template|null $template Template object. * @return string */ public function get_stylesheet_for_rendering( ?WP_Post $post = null, $template = null ): string { $email_theme_settings = $this->get_settings(); $css_presets = ''; // Font family classes. foreach ( $email_theme_settings['typography']['fontFamilies']['default'] as $font_family ) { $css_presets .= ".has-{$font_family['slug']}-font-family { font-family: {$font_family['fontFamily']}; } \n"; } // Font size classes. foreach ( $email_theme_settings['typography']['fontSizes']['default'] as $font_size ) { $css_presets .= ".has-{$font_size['slug']}-font-size { font-size: {$font_size['size']}; } \n"; } // Color palette classes. $color_definitions = array_merge( $email_theme_settings['color']['palette']['theme'], $email_theme_settings['color']['palette']['default'] ); foreach ( $color_definitions as $color ) { $css_presets .= ".has-{$color['slug']}-color { color: {$color['color']}; } \n"; $css_presets .= ".has-{$color['slug']}-background-color { background-color: {$color['color']}; } \n"; $css_presets .= ".has-{$color['slug']}-border-color { border-color: {$color['color']}; } \n"; } // Block specific styles. $css_blocks = ''; $blocks = $this->get_theme()->get_styles_block_nodes(); foreach ( $blocks as $block_metadata ) { $css_blocks .= $this->get_theme()->get_styles_for_block( $block_metadata ); } // Element specific styles. $elements_styles = $this->get_theme()->get_raw_data()['styles']['elements'] ?? array(); // Because the section styles is not a part of the output the `get_styles_block_nodes` method, we need to get it separately. if ( $template && $template->wp_id ) { $template_theme = (array) get_post_meta( $template->wp_id, 'mailpoet_email_theme', true ); $template_styles = (array) ( $template_theme['styles'] ?? array() ); $template_elements = $template_styles['elements'] ?? array(); $elements_styles = array_replace_recursive( (array) $elements_styles, (array) $template_elements ); } if ( $post ) { $post_theme = (array) get_post_meta( $post->ID, 'mailpoet_email_theme', true ); $post_styles = (array) ( $post_theme['styles'] ?? array() ); $post_elements = $post_styles['elements'] ?? array(); $elements_styles = array_replace_recursive( (array) $elements_styles, (array) $post_elements ); } $css_elements = ''; foreach ( $elements_styles as $key => $elements_style ) { $selector = $key; if ( 'button' === $key ) { $selector = '.wp-block-button'; $css_elements .= wp_style_engine_get_styles( $elements_style, array( 'selector' => '.wp-block-button' ) )['css']; // Add color to link element. $css_elements .= wp_style_engine_get_styles( array( 'color' => array( 'text' => $elements_style['color']['text'] ?? '' ) ), array( 'selector' => '.wp-block-button a' ) )['css']; continue; } switch ( $key ) { case 'heading': $selector = 'h1, h2, h3, h4, h5, h6'; break; case 'link': $selector = 'a:not(.button-link)'; break; } $css_elements .= wp_style_engine_get_styles( $elements_style, array( 'selector' => $selector ) )['css']; } $result = $css_presets . $css_blocks . $css_elements; // Because font-size can by defined by the clamp() function that is not supported in the e-mail clients, we need to replace it to the value. // Regular expression to match clamp() function and capture its max value. $pattern = '/clamp\([^,]+,\s*[^,]+,\s*([^)]+)\)/'; // Replace clamp() with its maximum value. $result = (string) preg_replace( $pattern, '$1', $result ); return $result; } /** * Translate font family slug to font family name. * * @param string $font_size Font size slug. * @return string */ public function translate_slug_to_font_size( string $font_size ): string { $settings = $this->get_settings(); foreach ( $settings['typography']['fontSizes']['default'] as $font_size_definition ) { if ( $font_size_definition['slug'] === $font_size ) { return $font_size_definition['size']; } } return $font_size; } /** * Translate color slug to color. * * @param string $color_slug Color slug. * @return string */ public function translate_slug_to_color( string $color_slug ): string { $settings = $this->get_settings(); $color_definitions = array_merge( $settings['color']['palette']['theme'], $settings['color']['palette']['default'] ); foreach ( $color_definitions as $color_definition ) { if ( $color_definition['slug'] === $color_slug ) { return strtolower( $color_definition['color'] ); } } return $color_slug; } /** * Returns the map of CSS variables and their values from the theme. * * @return array */ public function get_variables_values_map(): array { $variables_css = $this->get_theme()->get_stylesheet( array( 'variables' ) ); $map = array(); // Regular expression to match CSS variable definitions. $pattern = '/--(.*?):\s*(.*?);/'; if ( preg_match_all( $pattern, $variables_css, $matches, PREG_SET_ORDER ) ) { foreach ( $matches as $match ) { // '--' . $match[1] is the variable name, $match[2] is the variable value. $map[ '--' . $match[1] ] = $match[2]; } } return $map; } }