Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails
WCEmailPostsCleanup::run
Entry point for the db-update callback.
Always returns false (one-shot), matching the contract \WC_Install::run_update_callback_end() expects.
Method of the class: WCEmailPostsCleanup{}
No Hooks.
Returns
bool. Always false.
Usage
$result = WCEmailPostsCleanup::run( ?Email_Editor_Logger_Interface $logger ): bool;
- ?Email_Editor_Logger_Interface $logger
- .
Default:null
Changelog
| Since 11.1.0 | Introduced. |
WCEmailPostsCleanup::run() WCEmailPostsCleanup::run code WC 11.1.2
public static function run( ?Email_Editor_Logger_Interface $logger = null ): bool {
$logger = $logger ?? new Logger( wc_get_logger() );
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
$emails_by_id = $posts_manager->get_emails_by_id();
$deleted = 0;
$kept = 0;
foreach ( self::fetch_email_post_mappings() as $mapping ) {
try {
$option_name = (string) $mapping->option_name;
$post_id = (int) $mapping->option_value;
$email_type = self::email_type_from_option_name( $option_name );
// The SQL LIKE match is loose (each `_` is a single-char
// wildcard); never touch options that only resemble the
// mapping shape — they belong to someone else.
if ( null === $email_type ) {
continue;
}
if ( $post_id <= 0 ) {
delete_option( $option_name );
continue;
}
$post = get_post( $post_id );
if ( ! $post instanceof \WP_Post || Integration::EMAIL_POST_TYPE !== $post->post_type ) {
// Orphaned mapping.
delete_option( $option_name );
continue;
}
// A trashed copy no longer affects rendering; treat it as "revert to
// default". The email editor UI never trashes woo_email posts (its
// delete action permanently deletes via the
// `woocommerce_email_editor_trash_modal_should_permanently_delete`
// filter), so a trashed post slipped past that guard out-of-band.
if ( 'trash' === $post->post_status ) {
if ( wp_delete_post( $post->ID, true ) ) {
delete_option( $option_name );
++$deleted;
}
continue;
}
$email = $emails_by_id[ $email_type ] ?? null;
if ( ! $email instanceof \WC_Email ) {
// Cannot compute the canonical content (e.g. extension deactivated);
// keep the post — it keeps rendering from the DB as before.
update_post_meta( $post->ID, WCTransactionalEmailPostsManager::EMAIL_TYPE_META_KEY, $email_type );
++$kept;
continue;
}
if ( self::was_never_customized( $post, $email ) ) {
// When the deletion fails (or a `pre_delete_post` filter
// short-circuits it with a falsy value), keep the mapping —
// otherwise the post would linger published while the email
// falls back to the file template.
if ( ! wp_delete_post( $post->ID, true ) ) {
continue;
}
// `before_delete_post` also removes the mapping when the email
// editor feature is active; delete the option defensively for
// the case it isn't.
delete_option( $option_name );
++$deleted;
} else {
update_post_meta( $post->ID, WCTransactionalEmailPostsManager::EMAIL_TYPE_META_KEY, $email_type );
++$kept;
}
} catch ( \Throwable $e ) {
$logger->error(
sprintf(
'Email posts cleanup failed for mapping %s: %s',
(string) $mapping->option_name,
$e->getMessage()
),
array(
'option_name' => (string) $mapping->option_name,
'context' => 'email_posts_cleanup',
)
);
continue;
}
}
delete_transient( self::LEGACY_GENERATION_TRANSIENT );
$posts_manager->clear_caches();
$logger->info(
sprintf( 'Email posts cleanup finished: %d never-customized post(s) deleted, %d customized post(s) kept.', $deleted, $kept ),
array( 'context' => 'email_posts_cleanup' )
);
return false;
}