REDROOM
PHP 8.2.31
Path:
Logout
Edit File
Size: 17.08 KB
Close
/home/nshryvcy/radiantskinclinics.org/wp-content/plugins/woocommerce/src/Internal/EmailEditor/EmailApiController.php
Text
Base64
<?php declare( strict_types = 1 ); namespace Automattic\WooCommerce\Internal\EmailEditor; use Automattic\WooCommerce\EmailEditor\Validator\Builder; use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateDivergenceDetector; use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncRegistry; use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager; use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsGenerator; use WC_Email; use WP_Error; use WP_REST_Request; use WP_REST_Response; defined( 'ABSPATH' ) || exit; /** * API Controller for managing WooCommerce email templates via extending the post type API. * * @internal */ class EmailApiController { /** * The WooCommerce transactional email post manager. * * @var WCTransactionalEmailPostsManager|null */ private ?WCTransactionalEmailPostsManager $post_manager = null; /** * The WooCommerce transactional email posts generator. * * @var WCTransactionalEmailPostsGenerator|null */ private ?WCTransactionalEmailPostsGenerator $posts_generator = null; /** * Initialize the controller. * * @internal */ final public function init(): void { $this->post_manager = WCTransactionalEmailPostsManager::get_instance(); $this->posts_generator = new WCTransactionalEmailPostsGenerator(); } /** * Returns the data from wp_options table for the given post. * * @param array $post_data - Post data. * @return array - The email data. */ public function get_email_data( $post_data ): array { $email_type = $this->post_manager->get_email_type_from_post_id( $post_data['id'] ); $email = $this->get_email_by_type( $email_type ?? '' ); // When the email type is not found, it means that the email type is not supported. if ( ! $email ) { return array( 'subject' => null, 'subject_full' => null, 'subject_partial' => null, 'preheader' => null, 'default_subject' => null, 'email_type' => null, 'recipient' => null, 'cc' => null, 'bcc' => null, ); } $form_fields = $email->get_form_fields(); $enabled = $email->get_option( 'enabled' ); return array( 'enabled' => is_null( $enabled ) ? $email->is_enabled() : 'yes' === $enabled, 'is_manual' => $email->is_manual(), 'subject' => $email->get_option( 'subject' ), 'subject_full' => $email->get_option( 'subject_full' ), // For customer_refunded_order email type because it has two different subjects. 'subject_partial' => $email->get_option( 'subject_partial' ), 'preheader' => $email->get_option( 'preheader' ), 'default_subject' => $email->get_default_subject(), 'email_type' => $email_type, // Recipient is possible to set only for the specific type of emails. When the field `recipient` is set in the form fields, it means that the email type has a recipient field. 'recipient' => array_key_exists( 'recipient', $form_fields ) ? $email->get_option( 'recipient', get_option( 'admin_email' ) ) : null, 'cc' => $email->get_option( 'cc' ), 'bcc' => $email->get_option( 'bcc' ), ); } /** * Update WooCommerce specific option data by post name. * * @param array $data - Data that are stored in the wp_options table. * @param \WP_Post $post - WP_Post object. * @return \WP_Error|null Returns WP_Error if email validation fails, null otherwise. */ public function save_email_data( array $data, \WP_Post $post ): ?\WP_Error { $error = $this->validate_email_data( $data ); if ( is_wp_error( $error ) ) { return new \WP_Error( 'invalid_email_data', implode( ' ', $error->get_error_messages() ), array( 'status' => 400 ) ); } if ( ! array_key_exists( 'subject', $data ) && ! array_key_exists( 'preheader', $data ) ) { return null; } $email_type = $this->post_manager->get_email_type_from_post_id( $post->ID ); $email = $this->get_email_by_type( $email_type ?? '' ); if ( ! $email ) { return null; // not saving of type wc_email. Allow process to continue. } // Handle customer_refunded_order email type because it has two different subjects. if ( 'customer_refunded_order' === $email_type ) { if ( array_key_exists( 'subject_full', $data ) ) { $email->update_option( 'subject_full', $data['subject_full'] ); } if ( array_key_exists( 'subject_partial', $data ) ) { $email->update_option( 'subject_partial', $data['subject_partial'] ); } } elseif ( array_key_exists( 'subject', $data ) ) { $email->update_option( 'subject', $data['subject'] ); } if ( array_key_exists( 'preheader', $data ) ) { $email->update_option( 'preheader', $data['preheader'] ); } if ( array_key_exists( 'enabled', $data ) ) { $email->update_option( 'enabled', $data['enabled'] ? 'yes' : 'no' ); } if ( array_key_exists( 'recipient', $data ) ) { $email->update_option( 'recipient', $data['recipient'] ); } if ( array_key_exists( 'cc', $data ) ) { $email->update_option( 'cc', $data['cc'] ); } if ( array_key_exists( 'bcc', $data ) ) { $email->update_option( 'bcc', $data['bcc'] ); } return null; } /** * Validate the email data. * * @param array $data - The email data. * @return \WP_Error|null Returns WP_Error if email validation fails, null otherwise. */ private function validate_email_data( array $data ) { $error = new \WP_Error(); // Validate 'recipient' email(s) field. $invalid_recipients = $this->filter_invalid_email_addresses( $data['recipient'] ?? '' ); if ( ! empty( $invalid_recipients ) ) { $error_message = sprintf( // translators: %s will be replaced by comma-separated email addresses. For example, "invalidemail1@example.com,invalidemail2@example.com". __( 'One or more Recipient email addresses are invalid: “%s”. Please enter valid email addresses separated by commas.', 'woocommerce' ), implode( ',', $invalid_recipients ) ); $error->add( 'invalid_recipient_email_address', $error_message ); } // Validate 'cc' email(s) field. $invalid_cc = $this->filter_invalid_email_addresses( $data['cc'] ?? '' ); if ( ! empty( $invalid_cc ) ) { $error_message = sprintf( // translators: %s will be replaced by comma-separated email addresses. For example, "invalidemail1@example.com,invalidemail2@example.com". __( 'One or more CC email addresses are invalid: “%s”. Please enter valid email addresses separated by commas.', 'woocommerce' ), implode( ',', $invalid_cc ) ); $error->add( 'invalid_cc_email_address', $error_message ); } // Validate 'bcc' email(s) field. $invalid_bcc = $this->filter_invalid_email_addresses( $data['bcc'] ?? '' ); if ( ! empty( $invalid_bcc ) ) { $error_message = sprintf( // translators: %s will be replaced by comma-separated email addresses. For example, "invalidemail1@example.com,invalidemail2@example.com". __( 'One or more BCC email addresses are invalid: “%s”. Please enter valid email addresses separated by commas.', 'woocommerce' ), implode( ',', $invalid_bcc ) ); $error->add( 'invalid_bcc_email_address', $error_message ); } if ( $error->has_errors() ) { return $error; } return null; } /** * Filter in invalid email addresses from a comma-separated string. * * @param string $comma_separated_email_addresses - A comma-separated string of email addresses. * @return array - An array of invalid email addresses. */ private function filter_invalid_email_addresses( $comma_separated_email_addresses ) { $invalid_email_addresses = array(); if ( empty( trim( $comma_separated_email_addresses ) ) ) { return $invalid_email_addresses; } foreach ( explode( ',', $comma_separated_email_addresses ) as $email_address ) { if ( ! filter_var( trim( $email_address ), FILTER_VALIDATE_EMAIL ) ) { $invalid_email_addresses[] = trim( $email_address ); } } return $invalid_email_addresses; } /** * Get the schema for the WooCommerce email post data. * * @return array */ public function get_email_data_schema(): array { return Builder::object( array( 'subject' => Builder::string()->nullable(), 'subject_full' => Builder::string()->nullable(), // For customer_refunded_order email type because it has two different subjects. 'subject_partial' => Builder::string()->nullable(), 'preheader' => Builder::string()->nullable(), 'default_subject' => Builder::string()->nullable(), 'email_type' => Builder::string()->nullable(), 'recipient' => Builder::string()->nullable(), 'cc' => Builder::string()->nullable(), 'bcc' => Builder::string()->nullable(), ) )->to_array(); } /** * Get all WooCommerce emails. * * @return \WC_Email[] */ protected function get_emails(): array { return WC()->mailer()->get_emails(); } /** * Get the email object by ID. * * @param string $id - The email ID. * @return \WC_Email|null - The email object or null if not found. */ private function get_email_by_type( ?string $id ): ?WC_Email { foreach ( $this->get_emails() as $email ) { if ( $email->id === $id ) { return $email; } } return null; } /** * Register REST API routes for the email API controller. */ public function register_routes(): void { register_rest_route( 'woocommerce-email-editor/v1', '/emails/(?P<id>\d+)/default-content', array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'get_default_content_response' ), 'permission_callback' => function () { return current_user_can( 'manage_woocommerce' ); }, 'args' => array( 'id' => array( 'description' => __( 'The ID of the woo_email post.', 'woocommerce' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ), ), 'schema' => array( $this, 'get_default_content_schema' ), ) ); register_rest_route( 'woocommerce-email-editor/v1', '/emails/(?P<id>\d+)/reset', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( $this, 'reset_response' ), 'permission_callback' => function () { return current_user_can( 'manage_woocommerce' ); }, 'args' => array( 'id' => array( 'description' => __( 'The ID of the woo_email post.', 'woocommerce' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ), ), 'schema' => array( $this, 'get_reset_schema' ), ) ); } /** * Get the schema for the default content endpoint response. * * @return array */ public function get_default_content_schema(): array { return array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'woo_email_default_content', 'type' => 'object', 'properties' => array( 'content' => array( 'description' => __( 'The default block content for the email.', 'woocommerce' ), 'type' => 'string', 'readonly' => true, ), ), ); } /** * Return the default (plugin-distributed) block content for a woo_email post. * * @param WP_REST_Request $request The REST request. * @phpstan-param WP_REST_Request<array<string, mixed>> $request * @return WP_REST_Response|WP_Error */ public function get_default_content_response( WP_REST_Request $request ) { if ( ! ( $this->post_manager && $this->posts_generator ) ) { return new WP_Error( 'woocommerce_email_editor_not_initialized', __( 'Email editor is not initialized.', 'woocommerce' ), array( 'status' => 500 ) ); } $post_id = (int) $request->get_param( 'id' ); $email_type = $this->post_manager->get_email_type_from_post_id( $post_id ); $email = $this->get_email_by_type( $email_type ?? '' ); if ( ! $email ) { return new WP_Error( 'woocommerce_email_not_found', __( 'No email found for the given post ID.', 'woocommerce' ), array( 'status' => 404 ) ); } return new WP_REST_Response( array( 'content' => $this->posts_generator->get_email_template( $email ) ), 200 ); } /** * Get the schema for the reset endpoint response. * * @return array */ public function get_reset_schema(): array { return array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'woo_email_reset', 'type' => 'object', 'properties' => array( 'content' => array( 'description' => __( 'The canonical block content written to the post.', 'woocommerce' ), 'type' => 'string', 'readonly' => true, ), 'version' => array( 'description' => __( 'The core block template @version stamped on the post, or null when the email is not sync-enabled.', 'woocommerce' ), 'type' => array( 'string', 'null' ), 'readonly' => true, ), 'source_hash' => array( 'description' => __( 'sha1 of the canonical block content stamped on the post, or null when the email is not sync-enabled.', 'woocommerce' ), 'type' => array( 'string', 'null' ), 'readonly' => true, ), 'synced_at' => array( 'description' => __( 'UTC timestamp when the post was stamped (Y-m-d H:i:s), or null when the email is not sync-enabled.', 'woocommerce' ), 'type' => array( 'string', 'null' ), 'readonly' => true, ), 'status' => array( 'description' => __( 'The post-reset sync status (in_sync on success for sync-enabled emails, null otherwise).', 'woocommerce' ), 'type' => array( 'string', 'null' ), 'readonly' => true, ), ), ); } /** * Reset a `woo_email` post to its current core template render and (when sync-enabled) stamp sync meta. * * Writes the canonical post content (byte-identical to what * {@see WCTransactionalEmailPostsGenerator} would produce on a fresh recreate). For emails * that are opted in to template sync (registered in {@see WCEmailTemplateSyncRegistry}), * also stamps `_wc_email_template_version`, `_wc_email_template_source_hash`, * `_wc_email_last_synced_at`, and `_wc_email_template_status = in_sync`. Meta writes are * conditional on the post update succeeding, so a `wp_update_post` failure leaves the * post — and any pre-existing meta — untouched. * * Non-sync-enabled emails (e.g. third-party templates without an `@version` header) * still receive a successful content reset, just without the meta stamp. This mirrors * the pre-RSM-148 behaviour where the standalone REST PUT performed the content reset * and stamping was a separate side effect, preserving backward compatibility. * * @param WP_REST_Request $request The REST request. * @phpstan-param WP_REST_Request<array<string, mixed>> $request * @return WP_REST_Response|WP_Error * * @since 10.8.0 */ public function reset_response( WP_REST_Request $request ) { if ( ! ( $this->post_manager && $this->posts_generator ) ) { return new WP_Error( 'woocommerce_email_editor_not_initialized', __( 'Email editor is not initialized.', 'woocommerce' ), array( 'status' => 500 ) ); } $post_id = (int) $request->get_param( 'id' ); $email_type = $this->post_manager->get_email_type_from_post_id( $post_id ); $email = $this->get_email_by_type( $email_type ?? '' ); if ( ! $email ) { return new WP_Error( 'woocommerce_email_not_found', __( 'No email found for the given post ID.', 'woocommerce' ), array( 'status' => 404 ) ); } $canonical = WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email ); $sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( (string) $email_type ); $update_result = wp_update_post( array( 'ID' => $post_id, 'post_content' => $canonical, ), true ); if ( is_wp_error( $update_result ) ) { return new WP_Error( 'woocommerce_email_reset_failed', sprintf( /* translators: %s: underlying error message */ __( 'Failed to reset email content: %s', 'woocommerce' ), $update_result->get_error_message() ), array( 'status' => 500 ) ); } $source_hash = null; $synced_at = null; if ( null !== $sync_config ) { $source_hash = sha1( $canonical ); $synced_at = gmdate( 'Y-m-d H:i:s' ); update_post_meta( $post_id, WCEmailTemplateDivergenceDetector::VERSION_META_KEY, (string) $sync_config['version'] ); update_post_meta( $post_id, WCEmailTemplateDivergenceDetector::SOURCE_HASH_META_KEY, $source_hash ); update_post_meta( $post_id, WCEmailTemplateDivergenceDetector::LAST_SYNCED_AT_META_KEY, $synced_at ); update_post_meta( $post_id, WCEmailTemplateDivergenceDetector::STATUS_META_KEY, WCEmailTemplateDivergenceDetector::STATUS_IN_SYNC ); } return new WP_REST_Response( array( 'content' => $canonical, 'version' => null !== $sync_config ? (string) $sync_config['version'] : null, 'source_hash' => $source_hash, 'synced_at' => $synced_at, 'status' => null !== $sync_config ? WCEmailTemplateDivergenceDetector::STATUS_IN_SYNC : null, ), 200 ); } }
Save
Close
Exit & Reset
Text mode: syntax highlighting auto-detects file type.
Directory Contents
Dirs: 4 × Files: 9
Delete Selected
Select All
Select None
Sort:
Name
Size
Modified
Enable drag-to-move
Name
Size
Perms
Modified
Actions
EmailPatterns
DIR
-
drwxr-xr-x
2026-05-29 02:43:21
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
EmailTemplates
DIR
-
drwxr-xr-x
2026-05-29 02:43:21
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
PersonalizationTags
DIR
-
drwxr-xr-x
2026-05-29 02:43:21
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
WCTransactionalEmails
DIR
-
drwxr-xr-x
2026-05-29 02:43:21
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
BlockEmailRenderer.php
5.39 KB
lrw-r--r--
2025-11-24 23:10:10
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
EmailApiController.php
17.08 KB
lrw-r--r--
2026-05-05 14:26:50
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Integration.php
17.03 KB
lrw-r--r--
2026-05-05 14:26:50
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Logger.php
4.10 KB
lrw-r--r--
2025-09-01 23:44:48
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Package.php
1.64 KB
lrw-r--r--
2025-05-12 21:07:28
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
PageRenderer.php
4.62 KB
lrw-r--r--
2025-09-01 23:44:48
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
PersonalizationTagManager.php
2.20 KB
lrw-r--r--
2025-05-12 21:07:28
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
TransactionalEmailPersonalizer.php
3.38 KB
lrw-r--r--
2026-02-23 17:58:34
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
WooContentProcessor.php
4.77 KB
lrw-r--r--
2026-05-05 14:26:50
Edit
Download
Rename
Chmod
Change Date
Delete
OK
Cancel
recursive
OK
Cancel
recursive
OK
Cancel
Zip Selected
If ZipArchive is unavailable, a
.tar
will be created (no compression).