MailPoet\EmailEditor\Engine

Email_Editor{}WC 1.0

Email editor class.

Usage

$Email_Editor = new Email_Editor();
// use class methods

Methods

  1. public __construct(
  2. public extend_email_post_api()
  3. public extend_email_theme_styles( WP_Theme_JSON $theme, WP_Post $post )
  4. public get_current_post()
  5. private get_default_email_post_args()
  6. private get_post_types()
  7. public initialize()
  8. public load_email_preview_template( $template )
  9. private register_block_patterns()
  10. private register_block_templates()
  11. public register_email_editor_api_routes()
  12. private register_email_post_sent_status()
  13. private register_email_post_types()
  14. private register_personalization_tags()

Email_Editor{} code WC 9.8.1

class Email_Editor {
	public const MAILPOET_EMAIL_META_THEME_TYPE = 'mailpoet_email_theme';

	/**
	 * Property for the email API controller.
	 *
	 * @var Email_Api_Controller Email API controller.
	 */
	private Email_Api_Controller $email_api_controller;
	/**
	 * Property for the templates.
	 *
	 * @var Templates Templates.
	 */
	private Templates $templates;
	/**
	 * Property for the patterns.
	 *
	 * @var Patterns Patterns.
	 */
	private Patterns $patterns;
	/**
	 * Property for the send preview email controller.
	 *
	 * @var Send_Preview_Email Send Preview controller.
	 */
	private Send_Preview_Email $send_preview_email;

	/**
	 * Property for Personalization_Tags_Controller that allows initializing personalization tags.
	 *
	 * @var Personalization_Tags_Registry Personalization tags registry.
	 */
	private Personalization_Tags_Registry $personalization_tags_registry;

	/**
	 * Constructor.
	 *
	 * @param Email_Api_Controller          $email_api_controller Email API controller.
	 * @param Templates                     $templates Templates.
	 * @param Patterns                      $patterns Patterns.
	 * @param Send_Preview_Email            $send_preview_email Preview email controller.
	 * @param Personalization_Tags_Registry $personalization_tags_controller Personalization tags registry that allows initializing personalization tags.
	 */
	public function __construct(
		Email_Api_Controller $email_api_controller,
		Templates $templates,
		Patterns $patterns,
		Send_Preview_Email $send_preview_email,
		Personalization_Tags_Registry $personalization_tags_controller
	) {
		$this->email_api_controller          = $email_api_controller;
		$this->templates                     = $templates;
		$this->patterns                      = $patterns;
		$this->send_preview_email            = $send_preview_email;
		$this->personalization_tags_registry = $personalization_tags_controller;
	}

	/**
	 * Initialize the email editor.
	 *
	 * @return void
	 */
	public function initialize(): void {
		do_action( 'mailpoet_email_editor_initialized' );
		add_filter( 'mailpoet_email_editor_rendering_theme_styles', array( $this, 'extend_email_theme_styles' ), 10, 2 );
		$this->register_block_patterns();
		$this->register_email_post_types();
		$this->register_block_templates();
		$this->register_email_post_sent_status();
		$this->register_personalization_tags();
		$is_editor_page = apply_filters( 'mailpoet_is_email_editor_page', false );
		if ( $is_editor_page ) {
			$this->extend_email_post_api();
		}
		add_action( 'rest_api_init', array( $this, 'register_email_editor_api_routes' ) );
		add_filter( 'mailpoet_email_editor_send_preview_email', array( $this->send_preview_email, 'send_preview_email' ), 11, 1 ); // allow for other filter methods to take precedent.
		add_filter( 'single_template', array( $this, 'load_email_preview_template' ) );
	}

	/**
	 * Register block templates.
	 *
	 * @return void
	 */
	private function register_block_templates(): void {
		// Since we cannot currently disable blocks in the editor for specific templates, disable templates when viewing site editor. @see https://github.com/WordPress/gutenberg/issues/41062.
		if ( strstr( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) ), 'site-editor.php' ) === false ) {
			$post_types = array_column( $this->get_post_types(), 'name' );
			$this->templates->initialize( $post_types );
		}
	}

	/**
	 * Register block patterns.
	 *
	 * @return void
	 */
	private function register_block_patterns(): void {
		$this->patterns->initialize();
	}

	/**
	 * Register all custom post types that should be edited via the email editor
	 * The post types are added via mailpoet_email_editor_post_types filter.
	 *
	 * @return void
	 */
	private function register_email_post_types(): void {
		foreach ( $this->get_post_types() as $post_type ) {
			register_post_type(
				$post_type['name'],
				array_merge( $this->get_default_email_post_args(), $post_type['args'] )
			);
		}
	}

	/**
	 * Register all personalization tags registered via
	 * the mailpoet_email_editor_register_personalization_tags filter.
	 *
	 * @return void
	 */
	private function register_personalization_tags(): void {
		$this->personalization_tags_registry->initialize();
	}

	/**
	 * Returns the email post types.
	 *
	 * @return array
	 * @phpstan-return EmailPostType[]
	 */
	private function get_post_types(): array {
		$post_types = array();
		return apply_filters( 'mailpoet_email_editor_post_types', $post_types );
	}

	/**
	 * Returns the default arguments for email post types.
	 *
	 * @return array
	 */
	private function get_default_email_post_args(): array {
		return array(
			'public'                 => false,
			'hierarchical'           => false,
			'show_ui'                => true,
			'show_in_menu'           => false,
			'show_in_nav_menus'      => false,
			'supports'               => array( 'editor', 'title', 'custom-fields' ), // 'custom-fields' is required for loading meta fields via API.
			'has_archive'            => true,
			'show_in_rest'           => true, // Important to enable Gutenberg editor.
			'default_rendering_mode' => 'template-locked',
			'publicly_queryable'     => true,  // required by the preview in new tab feature.
		);
	}

	/**
	 * Register the 'sent' post status for emails.
	 *
	 * @return void
	 */
	private function register_email_post_sent_status(): void {
		$default_args = array(
			'public'                    => false,
			'exclude_from_search'       => true,
			'internal'                  => true, // for now, we hide it, if we use the status in the listings we may flip this and following values.
			'show_in_admin_all_list'    => false,
			'show_in_admin_status_list' => false,
			'private'                   => true, // required by the preview in new tab feature for sent post (newsletter). Posts are only visible to site admins and editors.
		);
		$args         = apply_filters( 'mailpoet_email_editor_post_sent_status_args', $default_args );
		register_post_status(
			'sent',
			$args
		);
	}

	/**
	 * Extends the email post types with email specific data.
	 *
	 * @return void
	 */
	public function extend_email_post_api() {
		$email_post_types = array_column( $this->get_post_types(), 'name' );
		register_rest_field(
			$email_post_types,
			'email_data',
			array(
				'get_callback'    => array( $this->email_api_controller, 'get_email_data' ),
				'update_callback' => array( $this->email_api_controller, 'save_email_data' ),
				'schema'          => $this->email_api_controller->get_email_data_schema(),
			)
		);
	}

	/**
	 * Registers the API route endpoint for the email editor
	 *
	 * @return void
	 */
	public function register_email_editor_api_routes() {
		register_rest_route(
			'mailpoet-email-editor/v1',
			'/send_preview_email',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this->email_api_controller, 'send_preview_email_data' ),
				'permission_callback' => function () {
					return current_user_can( 'edit_posts' );
				},
			)
		);
		register_rest_route(
			'mailpoet-email-editor/v1',
			'/get_personalization_tags',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this->email_api_controller, 'get_personalization_tags' ),
				'permission_callback' => function () {
					return current_user_can( 'edit_posts' );
				},
			)
		);
	}

	/**
	 * Extends the email theme styles with the email specific styles.
	 *
	 * @param WP_Theme_JSON $theme Email theme styles.
	 * @param WP_Post       $post Email post object.
	 * @return WP_Theme_JSON
	 */
	public function extend_email_theme_styles( WP_Theme_JSON $theme, WP_Post $post ): WP_Theme_JSON {
		$email_theme = get_post_meta( $post->ID, self::MAILPOET_EMAIL_META_THEME_TYPE, true );
		if ( $email_theme && is_array( $email_theme ) ) {
			$theme->merge( new WP_Theme_JSON( $email_theme ) );
		}
		return $theme;
	}

	/**
	 * Get the current post object
	 *
	 * @return array|mixed|WP_Post|null
	 */
	public function get_current_post() {
		if ( isset( $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$current_post = get_post( intval( $_GET['post'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- data valid
		} else {
			$current_post = $GLOBALS['post'];
		}
		return $current_post;
	}

	/**
	 * Use a custom page template for the email editor frontend rendering.
	 *
	 * @param string $template post template.
	 * @return string
	 */
	public function load_email_preview_template( $template ) {
		$post = $this->get_current_post();

		if ( ! $post instanceof \WP_Post ) {
			return $template;
		}

		$current_post_type = $post->post_type;

		$email_post_types = array_column( $this->get_post_types(), 'name' );

		if ( ! in_array( $current_post_type, $email_post_types, true ) ) {
			return $template;
		}

		add_filter(
			'mailpoet_email_editor_preview_post_template_html',
			function () use ( $post ) {
				// Generate HTML content for email editor post.
				return $this->send_preview_email->render_html( $post );
			}
		);

		return __DIR__ . '/Templates/single-email-post-template.php';
	}
}