๐Ÿ“ฆ olegfedak / eleventy-plugin-relate-collections

๐Ÿ“„ index.js ยท 99 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99module.exports = function (eleventyConfig, options = {}) {
    // Default configuration options
    const defaultOptions = {
        collectionName: "", // The name of the collection you want to modify
        relatedCollectionName: "", // An array of collections to search for relationships
        relatedCollectionKey: "", // A key or array of keys used to find relationships
        backRelate: false, // Enable the back-relation feature
    };

    const config = Object.assign({}, defaultOptions, options);

    // Add a custom Eleventy collection
    eleventyConfig.addCollection(config.collectionName, async (collection) => {
        // Get the target collection based on tags
        const targetCollection = collection.getFilteredByTag(config.collectionName);

        // Initialize an array to store related objects
        const modifiedCollection = await Promise.all(targetCollection.map(async (page) => {
            const relatedObjects = [];

            // Ensure relatedCollectionName and relatedCollectionKey are arrays
            if (!Array.isArray(config.relatedCollectionName)) {
                config.relatedCollectionName = [config.relatedCollectionName];
            }

            if (!Array.isArray(config.relatedCollectionKey)) {
                config.relatedCollectionKey = [config.relatedCollectionKey];
            }

            for (const relatedName of config.relatedCollectionName) {
                // Get the related collection
                const relatedCollection = collection.getFilteredByTag(relatedName);
                const relatedPages = [];

                // Iterate through items in the related collection
                for (const item of relatedCollection) {
                    for (const key of config.relatedCollectionKey) {
                        const relatedData = item.data[key];

                        // Check if the relatedData is an array and if it contains the page title
                        if (Array.isArray(relatedData)) {
                            if (relatedData.some(value => value && value.toLowerCase() === page.data.title.toLowerCase())) {
                                relatedPages.push(item);
                            }
                        } else {
                            // Check if the relatedData matches the page title
                            if (relatedData && relatedData.toLowerCase() === page.data.title.toLowerCase()) {
                                relatedPages.push(item);
                            }
                        }
                    }
                }

                // Create a related object with the related collection name and items
                const relatedObject = {
                    name: relatedName,
                    items: relatedPages,
                };

                relatedObjects.push(relatedObject);
            }

            // If backRelate is enabled, create back relations
            if (config.backRelate) {
                for (const relatedObject of relatedObjects) {
                    for (const relatedPage of relatedObject.items) {
                        if (!relatedPage.data.related) {
                            relatedPage.data.related = [];
                        }

                        // Find related data for the current collection
                        const relatedData = relatedPage.data.related.find(item => item.name === config.collectionName);

                        if (!relatedData) {
                            // If no related data exists, create a new entry
                            relatedPage.data.related.push({
                                name: config.collectionName,
                                items: [page],
                            });
                        } else {
                            // Check for uniqueness using an identifier (page.title in this example)
                            const isUnique = !relatedData.items.some(item => item.data.title === page.data.title);
                            if (isUnique) {
                                relatedData.items.push(page);
                            }
                        }
                    }
                }
            }

            // Set the related data for the current page
            page.data.related = relatedObjects;
            return page;
        }));

        return modifiedCollection;
    });
};