<?php declare(strict_types = 1);
namespace MailPoet\Newsletter\Preview;
if (!defined('ABSPATH')) exit;
use MailPoet\WooCommerce\NonPersistablePreviewData;
use MailPoet\WP\Functions as WPFunctions;
/**
* Provides dummy WooCommerce data for email previews.
* Uses WooCommerce filters when available, with fallback to default data.
*/
class WooCommerceDummyData {
private WPFunctions $wp;
public function __construct(
WPFunctions $wp
) {
$this->wp = $wp;
}
/**
* Get a dummy WooCommerce order with placeholder data for preview.
*
* @return \WC_Order|null Dummy order or null if WooCommerce is unavailable
*/
public function getOrder(): ?\WC_Order {
if (!class_exists(\WC_Order::class)) {
return null;
}
try {
// Keep the id at 0 so the order can't read from or write to a real order;
// get_order_number() provides the display number.
$order = new class extends \WC_Order {
use NonPersistablePreviewData;
public function get_order_number() { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- overrides WC_Order::get_order_number().
return '12345';
}
/** @return array<int, \stdClass> */
public function get_customer_order_notes() { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps -- overrides WC_Order::get_customer_order_notes(), at id 0 the parent would return every order note on the site.
return [];
}
};
$this->setOrderAddress($order);
$this->addOrderItems($order);
$this->setOrderMetadata($order);
return $order;
} catch (\Throwable $e) {
return null;
}
}
/**
* Get a dummy WooCommerce customer with placeholder data for preview.
*
* @return \WC_Customer|null Dummy customer or null if WooCommerce is unavailable
*/
public function getCustomer(): ?\WC_Customer {
if (!class_exists(\WC_Customer::class)) {
return null;
}
try {
$address = $this->getAddress();
$customer = new class extends \WC_Customer {
use NonPersistablePreviewData;
};
$customer->set_id(0);
// Set basic info
$customer->set_first_name($address['first_name']);
$customer->set_last_name($address['last_name']);
$customer->set_email($address['email']);
// Set billing address
$customer->set_billing_first_name($address['first_name']);
$customer->set_billing_last_name($address['last_name']);
$customer->set_billing_company($address['company']);
$customer->set_billing_address_1($address['address_1']);
$customer->set_billing_city($address['city']);
$customer->set_billing_state($address['state']);
$customer->set_billing_postcode($address['postcode']);
$customer->set_billing_country($address['country']);
$customer->set_billing_phone($address['phone']);
$customer->set_billing_email($address['email']);
// Set shipping address (same as billing)
$customer->set_shipping_first_name($address['first_name']);
$customer->set_shipping_last_name($address['last_name']);
$customer->set_shipping_company($address['company']);
$customer->set_shipping_address_1($address['address_1']);
$customer->set_shipping_city($address['city']);
$customer->set_shipping_state($address['state']);
$customer->set_shipping_postcode($address['postcode']);
$customer->set_shipping_country($address['country']);
return $customer;
} catch (\Throwable $e) {
return null;
}
}
/**
* Get dummy address data using WooCommerce filter with fallback.
*
* @return array{first_name: string, last_name: string, company: string, email: string, phone: string, address_1: string, city: string, postcode: string, country: string, state: string}
*/
private function getAddress(): array {
$default = [
'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',
];
$address = $this->wp->applyFilters('woocommerce_email_preview_dummy_address', $default, null);
if (!is_array($address)) {
return $default;
}
$result = $default;
foreach ($default as $key => $defaultValue) {
$value = $address[$key] ?? null;
if (is_scalar($value)) {
$result[$key] = (string)$value;
}
}
return $result;
}
/**
* Set billing and shipping address on order.
*/
private function setOrderAddress(\WC_Order $order): void {
$address = $this->getAddress();
// Billing
$order->set_billing_first_name($address['first_name']);
$order->set_billing_last_name($address['last_name']);
$order->set_billing_company($address['company']);
$order->set_billing_email($address['email']);
$order->set_billing_phone($address['phone']);
$order->set_billing_address_1($address['address_1']);
$order->set_billing_city($address['city']);
$order->set_billing_state($address['state']);
$order->set_billing_postcode($address['postcode']);
$order->set_billing_country($address['country']);
// Shipping (same as billing)
$order->set_shipping_first_name($address['first_name']);
$order->set_shipping_last_name($address['last_name']);
$order->set_shipping_company($address['company']);
$order->set_shipping_address_1($address['address_1']);
$order->set_shipping_city($address['city']);
$order->set_shipping_state($address['state']);
$order->set_shipping_postcode($address['postcode']);
$order->set_shipping_country($address['country']);
}
/**
* Set order metadata (status, totals, payment, etc.).
*/
private function setOrderMetadata(\WC_Order $order): void {
$order->set_status('completed');
$order->set_currency(function_exists('get_woocommerce_currency') ? get_woocommerce_currency() : 'USD');
$order->set_total('99.99');
$order->set_discount_total('10');
$order->set_shipping_total('5');
$order->set_date_created(time());
$order->set_payment_method('bacs');
$order->set_payment_method_title('Direct Bank Transfer');
}
/**
* Add dummy line items to the order.
* Uses WooCommerce filters when available, with fallback to default products.
*/
private function addOrderItems(\WC_Order $order): void {
if (!class_exists(\WC_Order_Item_Product::class)) {
return;
}
$product = $this->getProduct();
if ($product) {
$item = new \WC_Order_Item_Product();
$item->set_props([
'name' => $product->get_name(),
'product_id' => $product->get_id(),
'quantity' => 2,
'subtotal' => (string)((float)$product->get_price() * 2),
'total' => (string)((float)$product->get_price() * 2),
]);
$order->add_item($item);
}
$variation = $this->getProductVariation();
if ($variation) {
$item = new \WC_Order_Item_Product();
$item->set_props([
'name' => $variation->get_name(),
'product_id' => $variation->get_parent_id(),
'variation_id' => $variation->get_id(),
'quantity' => 1,
'subtotal' => $variation->get_price(),
'total' => $variation->get_price(),
]);
$order->add_item($item);
}
}
/**
* Get a dummy product using WooCommerce filter with fallback.
*/
private function getProduct(): ?\WC_Product {
if (!class_exists(\WC_Product::class)) {
return null;
}
// Try to get from filter first
$product = $this->wp->applyFilters('woocommerce_email_preview_dummy_product', null, null);
if ($product instanceof \WC_Product) {
return $product;
}
// Fallback: create default dummy product
$product = new class extends \WC_Product {
use NonPersistablePreviewData;
};
$product->set_name(__('Dummy Product', 'woocommerce'));
$product->set_price('25');
return $product;
}
/**
* Get a dummy product variation using WooCommerce filter with fallback.
*/
private function getProductVariation(): ?\WC_Product_Variation {
if (!class_exists(\WC_Product_Variation::class)) {
return null;
}
// Try to get from filter first
$variation = $this->wp->applyFilters('woocommerce_email_preview_dummy_product_variation', null, null);
if ($variation instanceof \WC_Product_Variation) {
return $variation;
}
// Fallback: create default dummy variation
$variation = new class extends \WC_Product_Variation {
use NonPersistablePreviewData;
};
$variation->set_name(__('Dummy Product Variation', 'woocommerce'));
$variation->set_price('20');
return $variation;
}
}