diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js
index d9c08051f..7a0b710e9 100644
--- a/docs/.vitepress/config.js
+++ b/docs/.vitepress/config.js
@@ -42,6 +42,10 @@ const sidebar = [
const sidebarApi = [
{ text: "Introduction", link: "/api/" },
+ {
+ text: "Indiekit.addCollection
",
+ link: "/api/add-collection",
+ },
{
text: "Indiekit.addEndpoint
",
link: "/api/add-endpoint",
diff --git a/docs/api/add-collection.md b/docs/api/add-collection.md
new file mode 100644
index 000000000..820b88f1d
--- /dev/null
+++ b/docs/api/add-collection.md
@@ -0,0 +1,18 @@
+---
+outline: deep
+---
+
+# `Indiekit.addCollection`
+
+This method is enables plug-ins to add a new collection to the MongoDB database for storing data.
+
+## Syntax
+
+```js
+new Indiekit.addCollection(name);
+```
+
+## Constructor
+
+`name`
+: Collection name. This cannot share the name of a collection added by another plug-in. Indiekit currently adds 2 collections: `posts` and `media`.
diff --git a/docs/api/index.md b/docs/api/index.md
index f9e5672a2..bdbf49753 100644
--- a/docs/api/index.md
+++ b/docs/api/index.md
@@ -12,6 +12,8 @@ A plug-in can provide any of the following features:
* [content store functions](add-store.md)
* [syndication functions](add-syndicator.md)
+A plug-in can also [add a collection](add-collection.md) to the MongoDb database.
+
## Anatomy of a plug-in
A plug-in is a `Class` with an `init()` function that is used to register endpoints, presets, stores and syndicators. You can also use the `init()` function to modify Indiekit’s [configuration](../configuration/index.md). For example:
diff --git a/packages/endpoint-json-feed/lib/controllers/json-feed.js b/packages/endpoint-json-feed/lib/controllers/json-feed.js
index 1138fa506..18c6bbbcd 100644
--- a/packages/endpoint-json-feed/lib/controllers/json-feed.js
+++ b/packages/endpoint-json-feed/lib/controllers/json-feed.js
@@ -3,7 +3,9 @@ import { jsonFeed } from "../json-feed.js";
export const jsonFeedController = async (request, response) => {
const { application } = request.app.locals;
const feedUrl = new URL(request.originalUrl, application.url).href;
- const posts = await application.posts
+
+ const postsCollection = application?.collections?.get("posts");
+ const posts = await postsCollection
.find({
"properties.post-status": {
$ne: "draft",
diff --git a/packages/endpoint-media/index.js b/packages/endpoint-media/index.js
index 6beef4db3..bfa2cc402 100644
--- a/packages/endpoint-media/index.js
+++ b/packages/endpoint-media/index.js
@@ -29,6 +29,7 @@ export default class MediaEndpoint {
}
init(Indiekit) {
+ Indiekit.addCollection("media");
Indiekit.addEndpoint(this);
// Use private value to register Micropub media endpoint path
diff --git a/packages/endpoint-media/lib/controllers/query.js b/packages/endpoint-media/lib/controllers/query.js
index 9a89160d0..b324c70b6 100644
--- a/packages/endpoint-media/lib/controllers/query.js
+++ b/packages/endpoint-media/lib/controllers/query.js
@@ -8,6 +8,7 @@ import { getMediaProperties } from "../utils.js";
*/
export const queryController = async (request, response, next) => {
const { application } = request.app.locals;
+ const mediaCollection = application.collections.get("media");
try {
const limit = Number(request.query.limit) || 0;
@@ -25,8 +26,8 @@ export const queryController = async (request, response, next) => {
// Return properties for a given URL
let mediaData;
- if (application.media) {
- mediaData = await application.media.findOne({
+ if (mediaCollection) {
+ mediaData = await mediaCollection.findOne({
"properties.url": url,
});
}
@@ -46,8 +47,8 @@ export const queryController = async (request, response, next) => {
hasPrev: false,
};
- if (application.media) {
- cursor = await getCursor(application.media, after, before, limit);
+ if (mediaCollection) {
+ cursor = await getCursor(mediaCollection, after, before, limit);
}
response.json({
diff --git a/packages/endpoint-media/lib/media-data.js b/packages/endpoint-media/lib/media-data.js
index 58660ab1a..5b48b1e13 100644
--- a/packages/endpoint-media/lib/media-data.js
+++ b/packages/endpoint-media/lib/media-data.js
@@ -17,7 +17,7 @@ export const mediaData = {
async create(application, publication, file) {
debug(`Create %O`, { file });
- const { media, timeZone } = application;
+ const { timeZone } = application;
const { me, postTypes } = publication;
// Media properties
@@ -59,9 +59,10 @@ export const mediaData = {
const mediaData = { path, properties };
// Add data to media collection (or replace existing if present)
- if (media) {
+ const mediaCollection = application?.collections?.get("media");
+ if (mediaCollection) {
const query = { "properties.url": properties.url };
- await media.replaceOne(query, mediaData, { upsert: true });
+ await mediaCollection.replaceOne(query, mediaData, { upsert: true });
}
return mediaData;
@@ -76,10 +77,10 @@ export const mediaData = {
async read(application, url) {
debug(`Read ${url}`);
- const { media } = application;
const query = { "properties.url": url };
- const mediaData = await media.findOne(query);
+ const mediaCollection = application?.collections?.get("media");
+ const mediaData = await mediaCollection.findOne(query);
if (!mediaData) {
throw IndiekitError.notFound(url);
}
@@ -96,10 +97,10 @@ export const mediaData = {
async delete(application, url) {
debug(`Delete ${url}`);
- const { media } = application;
const query = { "properties.url": url };
- const result = await media.deleteOne(query);
+ const mediaCollection = application?.collections?.get("media");
+ const result = await mediaCollection.deleteOne(query);
if (result?.deletedCount === 1) {
return true;
}
diff --git a/packages/endpoint-media/lib/media-type-count.js b/packages/endpoint-media/lib/media-type-count.js
index 91e5ffc39..216726669 100644
--- a/packages/endpoint-media/lib/media-type-count.js
+++ b/packages/endpoint-media/lib/media-type-count.js
@@ -1,12 +1,12 @@
export const mediaTypeCount = {
/**
* Count the number of media of a given type
- * @param {object} application - Application configuration
+ * @param {object} postsCollection - Posts database collection
* @param {object} properties - Media properties
* @returns {Promise