PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / EmailEditor / Integrations / MailPoet / Patterns / Pattern.php
mailpoet / lib / EmailEditor / Integrations / MailPoet / Patterns Last commit date
Library 1 month ago Pattern.php 1 month ago PatternsController.php 1 month ago index.php 1 year ago
Pattern.php
141 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\EmailEditor\Integrations\MailPoet\Patterns;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use Automattic\WooCommerce\EmailEditor\Engine\Patterns\Abstract_Pattern;
9 use MailPoet\EmailEditor\Integrations\MailPoet\Coupons\CouponBlock;
10 use MailPoet\Util\CdnAssetUrl;
11
12 abstract class Pattern extends Abstract_Pattern {
13 protected CdnAssetUrl $cdnAssetUrl;
14 protected $namespace = 'mailpoet';
15
16 public function __construct(
17 CdnAssetUrl $cdnAssetUrl
18 ) {
19 $this->cdnAssetUrl = $cdnAssetUrl;
20 }
21
22 /**
23 * Get the content to use when creating an email from this pattern.
24 * Override in subclasses to provide different insertion content than preview.
25 * By default, returns the same as get_content().
26 */
27 public function get_email_content(): string { // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
28 return $this->get_content();
29 }
30
31 /**
32 * @param string[] $imageNames CDN filenames for placeholder product images.
33 */
34 protected function getProductPlaceholderBlocks(array $imageNames): string {
35 $blocks = '';
36 foreach ($imageNames as $imageName) {
37 $blocks .= $this->getProductPlaceholderCard($imageName);
38 }
39 return $blocks;
40 }
41
42 /**
43 * Render placeholder products in a two-column grid.
44 *
45 * Uses 10px padding per column side (20px total gap) to match the WooCommerce
46 * email renderer's two-column grid (see class-product-collection.php).
47 * Pixel values are used instead of spacing presets for email client compatibility.
48 *
49 * @param string[] $imageNames CDN filenames for placeholder product images. Should contain an even number of items.
50 */
51 protected function getProductPlaceholderColumns(array $imageNames): string {
52 $rows = array_chunk($imageNames, 2);
53 $blocks = '';
54
55 foreach ($rows as $row) {
56 $cols = '';
57 foreach ($row as $index => $imageName) {
58 $isFirst = $index === 0;
59 $padding = $isFirst ? 'right' : 'left';
60 $style = 'padding-' . $padding . ':10px';
61 $cols .= '
62 <!-- wp:column {"style":{"spacing":{"padding":{"' . $padding . '":"10px"}}}} -->
63 <div class="wp-block-column" style="' . $style . '">' . $this->getProductPlaceholderCard($imageName) . '</div>
64 <!-- /wp:column -->';
65 }
66
67 $blocks .= '
68 <!-- wp:columns -->
69 <div class="wp-block-columns">' . $cols . '</div>
70 <!-- /wp:columns -->';
71 }
72
73 return $blocks;
74 }
75
76 /**
77 * Get a product collection block for recommended products.
78 *
79 * @param string $collection WooCommerce collection slug (e.g., 'best-sellers', 'new-arrivals')
80 * or a fully namespaced collection (e.g., OrderProductCollectionProcessor::COLLECTION_ORDER_CROSS_SELLS,
81 * resolved per order at send time). The query authored here is the fallback when an
82 * order-aware collection cannot be resolved.
83 * @param string $orderBy Order by field (e.g., 'date', 'popularity').
84 * @param int $perPage Number of products to show.
85 * @param int $columns Number of columns in the grid.
86 */
87 protected function getRecommendedProductCollectionBlock(string $collection, string $orderBy = 'date', int $perPage = 4, int $columns = 2): string {
88 $collectionSlug = strpos($collection, '/') !== false ? $collection : 'woocommerce/product-collection/' . $collection;
89 return '
90 <!-- wp:woocommerce/product-collection {"query":{"perPage":' . $perPage . ',"pages":1,"offset":0,"postType":"product","order":"desc","orderBy":"' . $orderBy . '","search":"","exclude":[],"inherit":false,"taxQuery":[],"isProductCollectionBlock":true,"featured":false,"woocommerceOnSale":false,"woocommerceStockStatus":["instock","onbackorder"],"woocommerceAttributes":[],"woocommerceHandPickedProducts":[],"filterable":false},"tagName":"div","displayLayout":{"type":"flex","columns":' . $columns . ',"shrinkColumns":true},"dimensions":{"widthType":"fill"},"collection":"' . $collectionSlug . '","hideControls":["inherit","attributes","keyword","order","default-order","featured","on-sale","stock-status","hand-picked","taxonomy","filterable","created","price-range"]} -->
91 <div class="wp-block-woocommerce-product-collection"><!-- wp:woocommerce/product-template -->
92 <!-- wp:woocommerce/product-image {"showSaleBadge":false,"imageSizing":"thumbnail","isDescendentOfQueryLoop":true,"style":{"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}}}} -->
93 <!-- wp:woocommerce/product-sale-badge {"align":"right"} /-->
94 <!-- /wp:woocommerce/product-image -->
95
96 <!-- wp:post-title {"textAlign":"center","isLink":true,"style":{"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}},"typography":{"fontSize":"24px"}},"__woocommerceNamespace":"woocommerce/product-collection/product-title"} /-->
97
98 <!-- wp:woocommerce/product-price {"isDescendentOfQueryLoop":true,"textAlign":"center","style":{"typography":{"fontSize":"14px"},"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}}}} /-->
99
100 <!-- wp:woocommerce/product-button {"textAlign":"center","isDescendentOfQueryLoop":true,"style":{"typography":{"fontSize":"16px"}}} /-->
101 <!-- /wp:woocommerce/product-template -->
102 </div>
103 <!-- /wp:woocommerce/product-collection -->
104 ';
105 }
106
107 protected function getGeneratedCouponBlock(string $align, int $amount, int $expiryDay): string {
108 $attributes = CouponBlock::withCreateNewDefaults([
109 'align' => $align,
110 'amount' => $amount,
111 'expiryDay' => $expiryDay,
112 ]);
113
114 return '
115 <!-- wp:woocommerce/coupon-code ' . wp_json_encode($attributes, JSON_UNESCAPED_SLASHES) . ' -->
116 <div class="wp-block-woocommerce-coupon-code align' . esc_attr($align) . '"><strong>' . CouponBlock::SAFE_PLACEHOLDER . '</strong></div>
117 <!-- /wp:woocommerce/coupon-code -->
118 ';
119 }
120
121 private function getProductPlaceholderCard(string $imageName): string {
122 $imageUrl = esc_url($this->cdnAssetUrl->generateCdnUrl('email-editor/' . $imageName));
123 $imageAlt = esc_attr__('Product placeholder', 'mailpoet');
124 $productName = __('Product name', 'mailpoet');
125
126 return '
127 <!-- wp:image {"sizeSlug":"full","style":{"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}}}} -->
128 <figure class="wp-block-image size-full" style="padding-top:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10)"><img src="' . $imageUrl . '" alt="' . $imageAlt . '"/></figure>
129 <!-- /wp:image -->
130
131 <!-- wp:heading {"textAlign":"center","style":{"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}},"typography":{"fontSize":"24px"}}} -->
132 <h2 class="wp-block-heading has-text-align-center" style="padding-top:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);font-size:24px">' . $productName . '</h2>
133 <!-- /wp:heading -->
134
135 <!-- wp:paragraph {"align":"center","style":{"typography":{"fontSize":"14px"},"spacing":{"padding":{"top":"var:preset|spacing|10","bottom":"var:preset|spacing|10"}}}} -->
136 <p class="has-text-align-center" style="padding-top:var(--wp--preset--spacing--10);padding-bottom:var(--wp--preset--spacing--10);font-size:14px">$99.90</p>
137 <!-- /wp:paragraph -->
138 ';
139 }
140 }
141