$product->set_downloadable( true );
/**
* A dummy downloadable WC_Product used in email preview.
*
* @param WC_Product $product The dummy downloadable product object.
* @param string $email_type The email type to preview.
*
* @since 10.3.0
*/
return apply_filters( 'woocommerce_email_preview_dummy_downloadable_product', $product, $this->email_type );
}
/**
* Get a dummy address.
*
* @return array
*/
private function get_dummy_address() {
$address = array(
'first_name' => 'John',
'last_name' => 'Doe',
'company' => 'Company',
'email' => 'john@company.com',
'phone' => '555-555-5555',
'address_1' => '123 Fake Street',
'city' => 'Faketown',
'postcode' => '12345',
'country' => 'US',
'state' => 'CA',
);
/**
* A dummy address used in email preview as billing and shipping one.
*
* @param array $address The dummy address.
* @param string $email_type The email type to preview.
*
* @since 9.6.0
*/
return apply_filters( 'woocommerce_email_preview_dummy_address', $address, $this->email_type );
}
/**
* Get the placeholders for the email preview.
*
* @param mixed $email_object The object to render email with. Can be WC_Order, WP_User, etc.
* @return array
*/
private function get_placeholders( $email_object ) {
$placeholders = array();
if ( is_a( $email_object, 'WC_Order' ) ) {
$placeholders['{order_date}'] = wc_format_datetime( $email_object->get_date_created() );
$placeholders['{order_number}'] = $email_object->get_order_number();
$placeholders['{order_billing_full_name}'] = $email_object->get_formatted_billing_full_name();
}
/**
* Placeholders for email preview.
*
* @param array $placeholders Placeholders for email subject.
* @param string $email_type The email type to preview.
* @param mixed $email_object The object to render email with. @since 9.9.0
*
* @since 9.6.0
*/
return apply_filters( 'woocommerce_email_preview_placeholders', $placeholders, $this->email_type, $email_object );
}
/**
* Set up filters for email preview.
*/
public function set_up_filters() {
$this->switch_to_site_locale();
// Show shipping address in preview emails unless preview shipping details are hidden.
add_filter( 'woocommerce_order_needs_shipping_address', array( $this, 'enable_shipping_address' ), 10, 3 );
// Email templates fetch product from the database to show additional information, which are not
// saved in WC_Order_Item_Product. This filter enables fetching that data also in email preview.
add_filter( 'woocommerce_order_item_product', array( $this, 'get_dummy_product_when_not_set' ), 10, 1 );
// Enable email preview mode - this way transient values are fetched for live preview.
add_filter( 'woocommerce_is_email_preview', array( $this, 'enable_preview_mode' ) );
// Use placeholder image included in WooCommerce files.
add_filter( 'woocommerce_order_item_thumbnail', array( $this, 'get_placeholder_image' ) );
// Make products in preview considered downloadable and provide dummy file so WC core shows downloads.
add_filter( 'woocommerce_is_downloadable', array( $this, 'force_product_downloadable' ), 10, 1 );
add_filter( 'woocommerce_product_file', array( $this, 'provide_dummy_product_file' ), 10, 1 );
// Provide dummy downloadable items for email preview.
add_filter( 'woocommerce_order_get_downloadable_items', array( $this, 'get_dummy_downloadable_items' ) );
}
/**
* Clean up filters after email preview.
*/
public function clean_up_filters() {
remove_filter( 'woocommerce_order_needs_shipping_address', array( $this, 'enable_shipping_address' ) );
remove_filter( 'woocommerce_order_item_product', array( $this, 'get_dummy_product_when_not_set' ), 10 );
remove_filter( 'woocommerce_is_email_preview', array( $this, 'enable_preview_mode' ) );
remove_filter( 'woocommerce_order_item_thumbnail', array( $this, 'get_placeholder_image' ) );
remove_filter( 'woocommerce_is_downloadable', array( $this, 'force_product_downloadable' ), 10 );
remove_filter( 'woocommerce_product_file', array( $this, 'provide_dummy_product_file' ), 10 );
remove_filter( 'woocommerce_order_get_downloadable_items', array( $this, 'get_dummy_downloadable_items' ), 10 );
$this->restore_locale();
}
/**
* Enable shipping address in the preview email unless shipping details are hidden.
*
* @param bool $needs_shipping_address Current value.
* @param array $hidden_shipping_methods Hidden shipping method IDs.
* @param WC_Order|null $order Order object.
* @return bool
*/
public function enable_shipping_address( $needs_shipping_address = true, $hidden_shipping_methods = array(), $order = null ) {
return $this->should_show_shipping_details( $order );
}
/**
* Check whether preview shipping details should be shown.
*
* @param WC_Order|null $order Preview order object.
* @return bool
*/
private function should_show_shipping_details( $order = null ) {
/**
* Filters whether shipping details should be shown in email previews.
*
* @since 11.0.0
*
* @param bool $show_shipping_details Whether to show shipping details. Default true.
* @param WC_Order|null $order Preview order object.
* @param string|null $email_type Email type being previewed.
*/
return (bool) apply_filters( 'woocommerce_email_preview_show_shipping_details', true, $order, $this->email_type );
}
/**
* Enable preview mode to use transient values in email-styles.php. Not using __return_true
* so we don't accidentally remove the same filter used by other plugin or theme.
*
* @return true
*/
public function enable_preview_mode() {
return true;
}
/**
* Get the placeholder image for the preview email.
*
* @return string
*/
public function get_placeholder_image() {
return '
';
}
/**
* Force products in preview to be considered downloadable so core renders downloads section.
*
* @param bool $is_downloadable Current value.
* @return bool
*/
public function force_product_downloadable( $is_downloadable ) {
/**
* Filters whether the current request is an email preview.
*
* When true, products should be considered downloadable so the downloads
* section renders in applicable emails during preview.
*
* @since 9.6.0
*
* @param bool $is_email_preview Whether preview mode is active.
*/
if ( apply_filters( 'woocommerce_is_email_preview', false ) ) {
return true;
}
return $is_downloadable;
}
/**
* Provide a dummy product file so product->has_file() returns true in preview.
*
* @param WC_Product_Download|array|null $file Current file object, array, or null.
* @return WC_Product_Download|array|null
*/
public function provide_dummy_product_file( $file ) {
/**
* Filters whether the current request is an email preview.
*
* When true, provide a dummy product file so downloadable template parts
* can render during preview.
*
* @since 9.6.0
*
* @param bool $is_email_preview Whether preview mode is active.
*/
if ( apply_filters( 'woocommerce_is_email_preview', false ) ) {
$dummy_file = new WC_Product_Download();
$dummy_file->set_id( 'preview-dummy' );
$dummy_file->set_name( __( 'Sample Download File.pdf', 'woocommerce' ) );
$dummy_file->set_file( 'sample-download.pdf' );
return $dummy_file;
}
return $file;
}
/**
* Get dummy downloadable items for email preview.
*
* @return array
*/
public function get_dummy_downloadable_items() {
$dummy_downloads = array(
array(
'product_name' => $this->get_dummy_downloadable_product()->get_name(),
'product_id' => $this->get_dummy_downloadable_product()->get_id(),
'download_url' => 'https://example.com/download',
'download_name' => __( 'Sample Download File.pdf', 'woocommerce' ),
'access_expires' => time() + ( 30 * DAY_IN_SECONDS ),
),
);
return $dummy_downloads;
}
/**
* Generate placeholder content for a specific email type, typically used in the email editor.
*
* Encapsulates the logic for setting the email type, generating raw content, applying styles,
* ensuring links open in new tabs, and handling errors based on WP_DEBUG.
*
* @param string $email_type_class_name The class name of the WC_Email type (e.g., 'WC_Email_Customer_Processing_Order').
* @return string The generated and styled HTML content.
* @throws \RuntimeException If content generation fails. If rendering fails.
*/
public function generate_placeholder_content( string $email_type_class_name ): string {
// Note: set_email_type can throw InvalidArgumentException.
$this->set_email_type( $email_type_class_name );
$woo_content_processor = wc_get_container()->get( WooContentProcessor::class );
$generate_content_closure = function () use ( $woo_content_processor ) {
// Note: If 'woocommerce_email_styles' filter was intentional and `prepare_css` isn't
// the intended callback, adjust accordingly. This assumes `prepare_css` applies styles
// needed for the Woo content block.
add_filter( 'woocommerce_email_styles', array( $woo_content_processor, 'prepare_css' ), 10, 2 );
$content = $woo_content_processor->get_woo_content( $this->get_email() );
$content = $this->get_email()->style_inline( $content );
$content = $this->ensure_links_open_in_new_tab( $content );
return $content;
};
$this->set_up_filters();
$message = '';
try {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$message = $generate_content_closure();
} else {
// Use output buffering to prevent partial renders with PHP notices or warnings when WP_DEBUG is off.
ob_start();
try {
$message = $generate_content_closure();
} catch ( Throwable $e ) {
ob_end_clean();
// Let the caller handle the exception.
throw new \RuntimeException( esc_html__( 'There was an error rendering the email editor placeholder content.', 'woocommerce' ), 0, $e );
}
ob_end_clean();
}
} finally {
$this->clean_up_filters();
}
return $message;
}
/**
* Switch to the site locale. This is to ensure the email is displayed
* in the store's language, as the customer would see it, not the admin's language.
*/
private function switch_to_site_locale() {
if ( ! $this->locale_switched ) {
wc_switch_to_site_locale();
$this->locale_switched = true;
}
}
/**
* Restore the original locale.
*/
private function restore_locale() {
if ( $this->locale_switched ) {
wc_restore_locale();
$this->locale_switched = false;
}
}
}
Fatal error: Uncaught Automattic\WooCommerce\Internal\DependencyManagement\ContainerException: Attempt to get an instance of class 'Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview', which doesn't exist. in /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php:105
Stack trace:
#0 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php(78): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get_core()
#1 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Container.php(68): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get()
#2 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreviewRestController.php(56): Automattic\WooCommerce\Container->get()
#3 [internal function]: Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreviewRestController->__construct()
#4 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php(162): ReflectionClass->newInstance()
#5 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php(119): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->instantiate_class_using_reflection()
#6 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php(78): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get_core()
#7 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Container.php(68): Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer->get()
#8 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(438): Automattic\WooCommerce\Container->get()
#9 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(272): WooCommerce->init_hooks()
#10 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(173): WooCommerce->__construct()
#11 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/woocommerce.php(55): WooCommerce::instance()
#12 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/woocommerce.php(70): WC()
#13 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-settings.php(597): include_once('...')
#14 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-config.php(102): require_once('...')
#15 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-load.php(50): require_once('...')
#16 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-blog-header.php(13): require_once('...')
#17 /var/www/vhosts/bininntaranaki.co.nz/httpdocs/index.php(17): require('...')
#18 {main}
thrown in /var/www/vhosts/bininntaranaki.co.nz/httpdocs/wp-content/plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php on line 105