Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails

WCTransactionalEmailPostsGenerator::create_draft │ public │ WC 11.1.0

Create a draft email post for the given email.

The draft is the editing scratchpad created when a user opens the email editor for an email type that has no saved post yet. It stays invisible to rendering (only published posts are used) and links to its email type solely via the _wc_email_type meta — the option mapping is written when the post is published, see Integration::save_email_mapping_on_publish().

Method of the class: WCTransactionalEmailPostsGenerator{}

No Hooks.

Returns

int. The post ID of the created draft.

Usage

$WCTransactionalEmailPostsGenerator = new WCTransactionalEmailPostsGenerator();
$WCTransactionalEmailPostsGenerator->create_draft( $email ): int;
$email(WC_Email) (required)
The transactional email instance.

Changelog

Since 11.1.0 Introduced.

WCTransactionalEmailPostsGenerator::create_draft() code WC 11.2.1

public function create_draft( \WC_Email $email ): int {
	$email_type = (string) $email->id;
	$post_data  = self::build_filtered_post_data( $email_type, $email );

	// The status is system-owned: it must stay `draft` so the post is
	// ignored by rendering until published, regardless of what the
	// `woocommerce_email_content_post_data` filter returns. A regular draft
	// is used instead of an auto-draft because the editor treats auto-draft
	// titles as placeholders and blanks them.
	$post_data['post_status'] = 'draft';

	if ( ! isset( $post_data['meta_input'] ) || ! is_array( $post_data['meta_input'] ) ) {
		$post_data['meta_input'] = array();
	}
	$post_data['meta_input'][ WCTransactionalEmailPostsManager::EMAIL_TYPE_META_KEY ] = $email_type;

	// Version + last-synced meta only apply to emails participating in
	// template update propagation. Their values don't depend on what
	// WordPress persists, so they can be written as part of the insert
	// (unlike the source hash below, which must match the saved content).
	$sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( $email_type );
	if ( null !== $sync_config ) {
		$post_data['meta_input'][ WCEmailTemplateDivergenceDetector::VERSION_META_KEY ]          = (string) $sync_config['version'];
		$post_data['meta_input'][ WCEmailTemplateDivergenceDetector::LAST_SYNCED_AT_META_KEY ]   = gmdate( 'Y-m-d H:i:s' );
		$post_data['meta_input'][ WCEmailTemplateDivergenceDetector::LAST_CORE_RENDER_META_KEY ] = (string) ( $post_data['post_content'] ?? '' );
	}

	$post_id = wp_insert_post( $post_data, true );

	if ( is_wp_error( $post_id ) ) {
		throw new \Exception( esc_html( $post_id->get_error_message() ) );
	}

	// The source hash is stamped for every draft — also for emails outside
	// the sync registry — because `was_never_edited()` checks rely on it;
	// the timestamp fallback breaks once a refresh or autosave touches
	// `post_modified`. It must reflect the post_content WordPress actually
	// persisted (post-`content_save_pre` filter chain), so it is stamped
	// after the insert returns, hashing the saved content.
	$saved_post = get_post( $post_id );
	$saved_body = $saved_post instanceof \WP_Post ? (string) $saved_post->post_content : (string) ( $post_data['post_content'] ?? '' );
	update_post_meta(
		(int) $post_id,
		WCEmailTemplateDivergenceDetector::SOURCE_HASH_META_KEY,
		sha1( $saved_body )
	);
	// Freshly created posts match canonical core by construction.
	update_post_meta(
		(int) $post_id,
		WCEmailTemplateDivergenceDetector::STATUS_META_KEY,
		WCEmailTemplateDivergenceDetector::STATUS_IN_SYNC
	);

	return (int) $post_id;
}