Node, React and MongoDB Headless CMS and Application Framework
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Operations for managing global documents (singleton content like site settings, navigation, etc.). Globals are perfect for content that appears site-wide and should only have one instance.
Retrieve a global document by its slug.
/**
* Find a global document by slug
* @param options - Find global options including slug and configuration
* @returns Promise resolving to the global document
*/
function findGlobal<T>(options: FindGlobalOptions): Promise<T>;
interface FindGlobalOptions {
/** The global slug to find */
slug: string;
/** How many levels deep to populate relationships */
depth?: number;
/** Locale for the operation */
locale?: string;
/** Fallback locale if content not found in specified locale */
fallbackLocale?: string;
/** User context for access control */
user?: User;
/** Whether to override access control */
overrideAccess?: boolean;
/** Whether to include hidden fields */
showHiddenFields?: boolean;
}Usage Examples:
import payload from "payload";
// Find header global
const header = await payload.findGlobal({
slug: "header",
});
console.log("Site title:", header.title);
console.log("Navigation:", header.navigation);
// Find with populated relationships
const headerWithLogos = await payload.findGlobal({
slug: "header",
depth: 1, // Populate logo uploads
});
// Find with specific locale
const frenchHeader = await payload.findGlobal({
slug: "header",
locale: "fr",
fallbackLocale: "en",
});
// Find in Express route with user context
app.get("/api/site-settings", async (req, res) => {
try {
const settings = await payload.findGlobal({
slug: "siteSettings",
user: req.user,
depth: 2,
});
res.json(settings);
} catch (error) {
res.status(404).json({ error: error.message });
}
});Update a global document with new data.
/**
* Update a global document
* @param options - Update global options including slug, data, and configuration
* @returns Promise resolving to the updated global document
*/
function updateGlobal<T>(options: UpdateGlobalOptions): Promise<T>;
interface UpdateGlobalOptions {
/** The global slug to update */
slug: string;
/** Updated data for the global */
data: any;
/** How many levels deep to populate relationships */
depth?: number;
/** Locale for the operation */
locale?: string;
/** Fallback locale if content not found in specified locale */
fallbackLocale?: string;
/** User context for access control */
user?: User;
/** Whether to override access control */
overrideAccess?: boolean;
/** Whether to include hidden fields */
showHiddenFields?: boolean;
}Usage Examples:
// Update header global
const updatedHeader = await payload.updateGlobal({
slug: "header",
data: {
title: "New Site Title",
tagline: "Updated tagline",
navigation: [
{ label: "Home", url: "/" },
{ label: "About", url: "/about" },
{ label: "Contact", url: "/contact" },
],
},
});
// Update with file uploads
const updatedSettings = await payload.updateGlobal({
slug: "siteSettings",
data: {
siteName: "My Updated Site",
logo: logoFileId, // ID of uploaded logo
socialMedia: {
twitter: "@mysite",
facebook: "mysite",
},
},
depth: 1, // Return populated logo
});
// Update with specific locale
const frenchFooter = await payload.updateGlobal({
slug: "footer",
data: {
copyright: "© 2023 Mon Site. Tous droits réservés.",
legalLinks: [
{ label: "Mentions légales", url: "/mentions-legales" },
{ label: "Politique de confidentialité", url: "/confidentialite" },
],
},
locale: "fr",
});
// Partial update in Express route
app.put("/api/site-settings", async (req, res) => {
try {
const updated = await payload.updateGlobal({
slug: "siteSettings",
data: req.body, // Partial update data
user: req.user,
});
res.json(updated);
} catch (error) {
res.status(400).json({ error: error.message });
}
});Globals are configured similarly to collections but represent singleton documents.
interface GlobalConfig {
/** Unique identifier for the global */
slug: string;
/** Array of field configurations */
fields: Field[];
/** Display label for the global */
label?: string;
/** Admin panel configuration */
admin?: GlobalAdminConfig;
/** Access control rules */
access?: GlobalAccessConfig;
/** Global-level hooks */
hooks?: GlobalHooks;
/** Document versioning configuration */
versions?: VersionsConfig | boolean;
/** Automatic timestamp fields */
timestamps?: boolean;
/** Database collection name override */
dbName?: string;
/** GraphQL configuration */
graphQL?: {
name?: string;
};
/** TypeScript configuration */
typescript?: {
interface?: string;
};
}Global Configuration Examples:
// Site header global
const HeaderGlobal: GlobalConfig = {
slug: "header",
label: "Site Header",
admin: {
description: "Configure the site header content and navigation",
group: "Layout",
},
access: {
read: () => true, // Public read access
update: ({ req: { user } }) => user?.role === "admin",
},
fields: [
{
name: "title",
type: "text",
required: true,
admin: {
description: "Main site title displayed in header",
},
},
{
name: "logo",
type: "upload",
relationTo: "media",
admin: {
description: "Site logo image",
},
},
{
name: "navigation",
type: "array",
label: "Navigation Links",
minRows: 1,
maxRows: 10,
fields: [
{
name: "label",
type: "text",
required: true,
},
{
name: "url",
type: "text",
required: true,
},
{
name: "newTab",
type: "checkbox",
defaultValue: false,
},
],
},
],
versions: {
drafts: true,
},
};
// Site settings global
const SiteSettingsGlobal: GlobalConfig = {
slug: "siteSettings",
label: "Site Settings",
admin: {
description: "General site configuration and settings",
group: "Configuration",
},
fields: [
{
name: "general",
type: "group",
label: "General Settings",
fields: [
{
name: "siteName",
type: "text",
required: true,
},
{
name: "siteDescription",
type: "textarea",
maxLength: 160,
},
{
name: "favicon",
type: "upload",
relationTo: "media",
},
],
},
{
name: "social",
type: "group",
label: "Social Media",
fields: [
{
name: "twitter",
type: "text",
},
{
name: "facebook",
type: "text",
},
{
name: "instagram",
type: "text",
},
],
},
{
name: "analytics",
type: "group",
label: "Analytics",
fields: [
{
name: "googleAnalyticsId",
type: "text",
},
{
name: "facebookPixelId",
type: "text",
},
],
},
],
hooks: {
afterChange: [
({ doc, req }) => {
// Clear cache when settings change
req.payload.logger.info("Site settings updated, clearing cache");
},
],
},
};
// Footer global with localization
const FooterGlobal: GlobalConfig = {
slug: "footer",
label: "Site Footer",
admin: {
description: "Configure footer content and links",
group: "Layout",
},
fields: [
{
name: "copyright",
type: "text",
required: true,
localized: true,
},
{
name: "links",
type: "array",
label: "Footer Links",
fields: [
{
name: "group",
type: "text",
required: true,
localized: true,
},
{
name: "links",
type: "array",
fields: [
{
name: "label",
type: "text",
required: true,
localized: true,
},
{
name: "url",
type: "text",
required: true,
},
],
},
],
},
{
name: "newsletter",
type: "group",
label: "Newsletter Signup",
fields: [
{
name: "enabled",
type: "checkbox",
defaultValue: false,
},
{
name: "title",
type: "text",
localized: true,
admin: {
condition: (data, siblingData) => siblingData?.enabled,
},
},
{
name: "description",
type: "textarea",
localized: true,
admin: {
condition: (data, siblingData) => siblingData?.enabled,
},
},
],
},
],
versions: true,
timestamps: true,
};Globals are perfect for site-wide configuration that needs to be easily editable:
// SEO defaults global
const SEODefaultsGlobal: GlobalConfig = {
slug: "seoDefaults",
label: "SEO Defaults",
fields: [
{
name: "title",
type: "text",
required: true,
},
{
name: "description",
type: "textarea",
maxLength: 160,
},
{
name: "ogImage",
type: "upload",
relationTo: "media",
},
{
name: "twitterHandle",
type: "text",
},
],
};
// Theme settings global
const ThemeSettingsGlobal: GlobalConfig = {
slug: "themeSettings",
label: "Theme Settings",
fields: [
{
name: "colorScheme",
type: "select",
options: [
{ label: "Light", value: "light" },
{ label: "Dark", value: "dark" },
{ label: "Auto", value: "auto" },
],
defaultValue: "light",
},
{
name: "primaryColor",
type: "text",
defaultValue: "#007bff",
},
{
name: "fonts",
type: "group",
fields: [
{
name: "heading",
type: "text",
defaultValue: "Inter",
},
{
name: "body",
type: "text",
defaultValue: "Inter",
},
],
},
],
};// Next.js example - fetch global data
export async function getStaticProps() {
const header = await payload.findGlobal({
slug: "header",
depth: 1,
});
const siteSettings = await payload.findGlobal({
slug: "siteSettings",
});
return {
props: {
header,
siteSettings,
},
revalidate: 300, // Revalidate every 5 minutes
};
}
// React component using global data
function Layout({ children, header, siteSettings }) {
return (
<html>
<head>
<title>{siteSettings.general.siteName}</title>
<meta name="description" content={siteSettings.general.siteDescription} />
<link rel="icon" href={siteSettings.general.favicon?.url} />
</head>
<body>
<header>
<img src={header.logo?.url} alt={header.title} />
<nav>
{header.navigation.map((item, index) => (
<a
key={index}
href={item.url}
target={item.newTab ? "_blank" : "_self"}
>
{item.label}
</a>
))}
</nav>
</header>
<main>{children}</main>
<footer>
<p>{footer.copyright}</p>
</footer>
</body>
</html>
);
}Install with Tessl CLI
npx tessl i tessl/npm-payload