payload-plugin-newsletter 0.17.3 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/dist/collections.cjs +91 -6
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +91 -6
- package/dist/collections.js.map +1 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +92 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +92 -7
- package/dist/index.js.map +1 -1
- package/dist/types.d.cts +18 -0
- package/dist/types.d.ts +18 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
## [0.18.0] - 2025-07-30
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **Media Field Population in Custom Blocks** - Fixed critical issue where media fields in custom blocks weren't populated during email conversion
|
|
5
|
+
- Added automatic media field population in preview endpoint before email conversion
|
|
6
|
+
- Media fields now receive full media objects with URLs instead of just ID strings
|
|
7
|
+
- Added `populateFields` option to `BroadcastCustomizations` interface for configurable field population
|
|
8
|
+
- Added recursive population support for array fields containing upload fields
|
|
9
|
+
- Comprehensive logging for media population success and failures
|
|
10
|
+
- Both email previews and sent emails now properly populate media relationships
|
|
11
|
+
|
|
12
|
+
### Enhanced
|
|
13
|
+
- **Preview Endpoint** - Significantly improved custom block support
|
|
14
|
+
- Preview endpoint now populates media fields before calling custom block converters
|
|
15
|
+
- Custom blocks with images now display correctly in email previews
|
|
16
|
+
- Added detailed logging for debugging media population issues
|
|
17
|
+
|
|
18
|
+
- **Broadcast Sync Logic** - Applied media population to all broadcast operations
|
|
19
|
+
- Create operation now populates media fields before provider sync
|
|
20
|
+
- Update operation populates media fields when content changes
|
|
21
|
+
- Deferred create operation (empty → content) now handles media population
|
|
22
|
+
- Ensures consistency between previews and actual sent emails
|
|
23
|
+
|
|
24
|
+
### Technical
|
|
25
|
+
- **New Helper Functions**
|
|
26
|
+
- `populateMediaFields()` - Recursively finds and populates upload fields in Lexical content
|
|
27
|
+
- `populateBlockMediaFields()` - Handles individual block media field population
|
|
28
|
+
- Support for both direct upload fields and upload fields within arrays
|
|
29
|
+
- Automatic detection of upload fields based on custom block configuration
|
|
30
|
+
- MongoDB ObjectId pattern matching for field population decisions
|
|
31
|
+
|
|
32
|
+
### Types
|
|
33
|
+
- **Enhanced BroadcastCustomizations Interface**
|
|
34
|
+
- Added `populateFields` option with string array or function signature
|
|
35
|
+
- Comprehensive documentation with usage examples
|
|
36
|
+
- Support for block-type-specific field population logic
|
|
37
|
+
|
|
38
|
+
### Breaking Changes
|
|
39
|
+
- None - all changes are backward compatible and additive
|
|
40
|
+
|
|
41
|
+
## [0.17.4] - 2025-07-30
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **Resolved Lint Errors** - Fixed CI/CD build failures caused by lint errors
|
|
45
|
+
- Removed unused imports from `endpoints/broadcasts/index.ts`
|
|
46
|
+
- Prefixed unused `collectionSlug` parameter with underscore in `preview.ts`
|
|
47
|
+
- Ensures clean build and successful npm publish
|
|
48
|
+
|
|
1
49
|
## [0.17.3] - 2025-07-30
|
|
2
50
|
|
|
3
51
|
### Fixed
|
package/dist/collections.cjs
CHANGED
|
@@ -1625,7 +1625,87 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
|
|
|
1625
1625
|
};
|
|
1626
1626
|
|
|
1627
1627
|
// src/endpoints/broadcasts/preview.ts
|
|
1628
|
-
|
|
1628
|
+
async function populateMediaFields(content, payload, config) {
|
|
1629
|
+
if (!content || typeof content !== "object") return content;
|
|
1630
|
+
if (content.root?.children) {
|
|
1631
|
+
for (const child of content.root.children) {
|
|
1632
|
+
await populateBlockMediaFields(child, payload, config);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return content;
|
|
1636
|
+
}
|
|
1637
|
+
async function populateBlockMediaFields(node, payload, config) {
|
|
1638
|
+
if (node.type === "block" && node.fields) {
|
|
1639
|
+
const blockType = node.fields.blockType || node.fields.blockName;
|
|
1640
|
+
const customBlocks = config.customizations?.broadcasts?.customBlocks || [];
|
|
1641
|
+
const blockConfig = customBlocks.find((b) => b.slug === blockType);
|
|
1642
|
+
if (blockConfig && blockConfig.fields) {
|
|
1643
|
+
for (const field of blockConfig.fields) {
|
|
1644
|
+
if (field.type === "upload" && field.relationTo && node.fields[field.name]) {
|
|
1645
|
+
const fieldValue = node.fields[field.name];
|
|
1646
|
+
if (typeof fieldValue === "string" && fieldValue.match(/^[a-f0-9]{24}$/i)) {
|
|
1647
|
+
try {
|
|
1648
|
+
const media = await payload.findByID({
|
|
1649
|
+
collection: field.relationTo,
|
|
1650
|
+
id: fieldValue,
|
|
1651
|
+
depth: 0
|
|
1652
|
+
});
|
|
1653
|
+
if (media) {
|
|
1654
|
+
node.fields[field.name] = media;
|
|
1655
|
+
payload.logger?.info(`Populated ${field.name} for block ${blockType}:`, {
|
|
1656
|
+
mediaId: fieldValue,
|
|
1657
|
+
mediaUrl: media.url,
|
|
1658
|
+
filename: media.filename
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
} catch (error) {
|
|
1662
|
+
payload.logger?.error(`Failed to populate ${field.name} for block ${blockType}:`, error);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
if (field.type === "array" && field.fields) {
|
|
1667
|
+
const arrayValue = node.fields[field.name];
|
|
1668
|
+
if (Array.isArray(arrayValue)) {
|
|
1669
|
+
for (const arrayItem of arrayValue) {
|
|
1670
|
+
if (arrayItem && typeof arrayItem === "object") {
|
|
1671
|
+
for (const arrayField of field.fields) {
|
|
1672
|
+
if (arrayField.type === "upload" && arrayField.relationTo && arrayItem[arrayField.name]) {
|
|
1673
|
+
const arrayFieldValue = arrayItem[arrayField.name];
|
|
1674
|
+
if (typeof arrayFieldValue === "string" && arrayFieldValue.match(/^[a-f0-9]{24}$/i)) {
|
|
1675
|
+
try {
|
|
1676
|
+
const media = await payload.findByID({
|
|
1677
|
+
collection: arrayField.relationTo,
|
|
1678
|
+
id: arrayFieldValue,
|
|
1679
|
+
depth: 0
|
|
1680
|
+
});
|
|
1681
|
+
if (media) {
|
|
1682
|
+
arrayItem[arrayField.name] = media;
|
|
1683
|
+
payload.logger?.info(`Populated array ${arrayField.name} for block ${blockType}:`, {
|
|
1684
|
+
mediaId: arrayFieldValue,
|
|
1685
|
+
mediaUrl: media.url,
|
|
1686
|
+
filename: media.filename
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
} catch (error) {
|
|
1690
|
+
payload.logger?.error(`Failed to populate array ${arrayField.name} for block ${blockType}:`, error);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (node.children) {
|
|
1703
|
+
for (const child of node.children) {
|
|
1704
|
+
await populateBlockMediaFields(child, payload, config);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
|
|
1629
1709
|
return {
|
|
1630
1710
|
path: "/preview",
|
|
1631
1711
|
method: "post",
|
|
@@ -1640,7 +1720,9 @@ var createBroadcastPreviewEndpoint = (config, collectionSlug) => {
|
|
|
1640
1720
|
}, { status: 400 });
|
|
1641
1721
|
}
|
|
1642
1722
|
const mediaUrl = req.payload.config.serverURL ? `${req.payload.config.serverURL}/api/media` : "/api/media";
|
|
1643
|
-
|
|
1723
|
+
req.payload.logger?.info("Populating media fields for email preview...");
|
|
1724
|
+
const populatedContent = await populateMediaFields(content, req.payload, config);
|
|
1725
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
1644
1726
|
wrapInTemplate: true,
|
|
1645
1727
|
preheader,
|
|
1646
1728
|
mediaUrl,
|
|
@@ -1939,8 +2021,9 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1939
2021
|
}
|
|
1940
2022
|
const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
|
|
1941
2023
|
const provider = new BroadcastApiProvider2(providerConfig);
|
|
1942
|
-
req.payload.logger.info("
|
|
1943
|
-
const
|
|
2024
|
+
req.payload.logger.info("Populating media fields and converting content to HTML...");
|
|
2025
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2026
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
1944
2027
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
1945
2028
|
});
|
|
1946
2029
|
if (!htmlContent || htmlContent.trim() === "") {
|
|
@@ -2039,7 +2122,8 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
2039
2122
|
return doc;
|
|
2040
2123
|
}
|
|
2041
2124
|
req.payload.logger.info("Creating broadcast in provider (deferred from initial create)...");
|
|
2042
|
-
const
|
|
2125
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2126
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
2043
2127
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
2044
2128
|
});
|
|
2045
2129
|
if (!htmlContent || htmlContent.trim() === "") {
|
|
@@ -2100,7 +2184,8 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
2100
2184
|
updates.preheader = doc.contentSection?.preheader;
|
|
2101
2185
|
}
|
|
2102
2186
|
if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
|
|
2103
|
-
|
|
2187
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2188
|
+
updates.content = await convertToEmailSafeHtml(populatedContent, {
|
|
2104
2189
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
2105
2190
|
});
|
|
2106
2191
|
}
|