diff --git a/packages/php/email-editor/src/Engine/class-user-theme.php b/packages/php/email-editor/src/Engine/class-user-theme.php new file mode 100644 index 0000000000..7bccb89ae0 --- /dev/null +++ b/packages/php/email-editor/src/Engine/class-user-theme.php @@ -0,0 +1,95 @@ + 3, + 'isGlobalStylesUserThemeJSON' => true, + ); + + /** + * Core theme loaded from the WordPress core. + * + * @var WP_Post | null + */ + private ?WP_Post $user_theme_post = null; + + /** + * Getter for user theme. + * + * @throws \Exception If the user theme post cannot be created. + * @return WP_Theme_JSON + */ + public function get_theme(): WP_Theme_JSON { + $post = $this->get_user_theme_post(); + $theme_data = json_decode( $post->post_content, true ); + if ( ! is_array( $theme_data ) ) { + $theme_data = self::INITIAL_THEME_DATA; + } + return new WP_Theme_JSON( $theme_data, 'custom' ); + } + + /** + * Getter for user theme post. + * If the post does not exist, it will be created. + * + * @throws \Exception If the user theme post cannot be created. + * @return WP_Post + */ + public function get_user_theme_post(): WP_Post { + $this->ensure_theme_post(); + if ( ! $this->user_theme_post instanceof WP_Post ) { + throw new \Exception( 'Error creating user theme post' ); + } + return $this->user_theme_post; + } + + /** + * Ensures that the user theme post exists and is loaded. + * + * @throws \Exception If the user theme post cannot be created. + */ + private function ensure_theme_post(): void { + if ( $this->user_theme_post ) { + return; + } + $this->user_theme_post = get_page_by_path( self::USER_THEME_POST_NAME, OBJECT, 'wp_global_styles' ); + if ( $this->user_theme_post instanceof WP_Post ) { + return; + } + $post_data = array( + 'post_title' => __( 'Custom Email Styles', 'mailpoet' ), + 'post_name' => self::USER_THEME_POST_NAME, + 'post_content' => (string) wp_json_encode( self::INITIAL_THEME_DATA, JSON_FORCE_OBJECT ), + 'post_status' => 'publish', + 'post_type' => 'wp_global_styles', + ); + + /** + * The doc is needed since PHPStan thinks that wp_insert_post can't return WP_Error. + * + * @var int|\WP_Error $post_id + */ + $post_id = wp_insert_post( $post_data ); + + if ( is_wp_error( $post_id ) ) { + throw new \Exception( 'Error creating user theme post: ' . esc_html( $post_id->get_error_message() ) ); + } + + $this->user_theme_post = get_post( $post_id ); + } +} diff --git a/packages/php/email-editor/tests/integration/Engine/User_Theme_Test.php b/packages/php/email-editor/tests/integration/Engine/User_Theme_Test.php new file mode 100644 index 0000000000..fcb34a6b9e --- /dev/null +++ b/packages/php/email-editor/tests/integration/Engine/User_Theme_Test.php @@ -0,0 +1,87 @@ +user_theme = new User_Theme(); + } + + /** + * Test it can create and return a user theme post + */ + public function testItCreatesUserThemePostLazily(): void { + $post = $this->user_theme->get_user_theme_post(); + $this->assertInstanceOf( \WP_Post::class, $post ); + $post_content = json_decode( $post->post_content, true ); + $this->assertIsArray( $post_content ); + $this->assertArrayHasKey( 'version', $post_content ); + $this->assertEquals( 3, $post_content['version'] ); + $this->assertArrayHasKey( 'isGlobalStylesUserThemeJSON', $post_content ); + $this->assertTrue( $post_content['isGlobalStylesUserThemeJSON'] ); + } + + /** + * Test it fetches previously stored data + */ + public function testItFetchesPreviouslyStoredData(): void { + $styles_data = array( + 'version' => 3, + 'isGlobalStylesUserThemeJSON' => true, + 'styles' => array( + 'color' => array( + 'background' => '#000000', + 'text' => '#ffffff', + ), + ), + ); + $post_data = array( + 'post_title' => __( 'Custom Email Styles', 'mailpoet' ), + 'post_name' => 'wp-global-styles-mailpoet-email', + 'post_content' => (string) wp_json_encode( $styles_data, JSON_FORCE_OBJECT ), + 'post_status' => 'publish', + 'post_type' => 'wp_global_styles', + ); + wp_insert_post( $post_data ); + + $post = $this->user_theme->get_user_theme_post(); + $this->assertInstanceOf( \WP_Post::class, $post ); + $post_content = json_decode( $post->post_content, true ); + $this->assertIsArray( $post_content ); + $this->assertArrayHasKey( 'version', $post_content ); + $this->assertEquals( 3, $post_content['version'] ); + $this->assertArrayHasKey( 'isGlobalStylesUserThemeJSON', $post_content ); + $this->assertTrue( $post_content['isGlobalStylesUserThemeJSON'] ); + $this->assertEquals( $styles_data['styles'], $post_content['styles'] ); + } + + /** + * Test it returns the user WP_Theme_JSON + */ + public function testItCreatesThemeJson(): void { + $theme = $this->user_theme->get_theme(); + $this->assertInstanceOf( \WP_Theme_JSON::class, $theme ); + $raw = $theme->get_raw_data(); + $this->assertArrayHasKey( 'version', $raw ); + } +} diff --git a/packages/php/email-editor/tests/integration/_bootstrap.php b/packages/php/email-editor/tests/integration/_bootstrap.php index 0a81e734f9..36c0276d30 100644 --- a/packages/php/email-editor/tests/integration/_bootstrap.php +++ b/packages/php/email-editor/tests/integration/_bootstrap.php @@ -28,6 +28,7 @@ use MailPoet\EmailEditor\Engine\Templates\Template_Preview; use MailPoet\EmailEditor\Engine\Templates\Templates; use MailPoet\EmailEditor\Engine\Templates\Utils; use MailPoet\EmailEditor\Engine\Theme_Controller; +use MailPoet\EmailEditor\Engine\User_Theme; use MailPoet\EmailEditor\Integrations\Core\Initializer; use MailPoet\EmailEditor\Integrations\MailPoet\Blocks\BlockTypesController; use MailPoet\EmailEditor\Engine\Send_Preview_Email; @@ -170,6 +171,12 @@ abstract class MailPoetTest extends \Codeception\TestCase\Test { // phpcs:ignore return new Theme_Controller(); } ); + $container->set( + User_Theme::class, + function () { + return new User_Theme(); + } + ); $container->set( Settings_Controller::class, function ( $container ) {